Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 44 additions & 17 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use bitcoin::constants::ChainHash;
use bitcoin::script::{Builder, Script, ScriptBuf, WScriptHash};
use bitcoin::sighash::EcdsaSighashType;
use bitcoin::transaction::{Transaction, TxOut};
use bitcoin::Witness;
use bitcoin::{Weight, Witness};

use bitcoin::hash_types::{BlockHash, Txid};
use bitcoin::hashes::sha256::Hash as Sha256;
Expand Down Expand Up @@ -59,14 +59,13 @@ use crate::ln::channelmanager::{
use crate::ln::funding::FundingTxInput;
#[cfg(splicing)]
use crate::ln::funding::SpliceContribution;
#[cfg(splicing)]
use crate::ln::interactivetxs::{
calculate_change_output_value, AbortReason, InteractiveTxMessageSend,
};
use crate::ln::interactivetxs::{
get_output_weight, InteractiveTxConstructor, InteractiveTxConstructorArgs,
InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
calculate_change_output_value, get_output_weight, InteractiveTxConstructor,
InteractiveTxConstructorArgs, InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput,
TX_COMMON_FIELDS_WEIGHT,
};
#[cfg(splicing)]
use crate::ln::interactivetxs::{AbortReason, InteractiveTxMessageSend};
use crate::ln::msgs;
use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
use crate::ln::onion_utils::{
Expand Down Expand Up @@ -6353,7 +6352,11 @@ impl FundingNegotiationContext {
.our_funding_inputs
.into_iter()
.map(|FundingTxInput { utxo, sequence, prevtx }| {
(TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() }, prevtx)
(
TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() },
prevtx,
Weight::from_wu(utxo.satisfaction_weight),
)
})
.collect();

Expand Down Expand Up @@ -10116,7 +10119,7 @@ where
#[rustfmt::skip]
pub fn is_awaiting_initial_mon_persist(&self) -> bool {
if !self.is_awaiting_monitor_update() { return false; }
if matches!(
if self.context.channel_state.is_interactive_signing() || matches!(
self.context.channel_state, ChannelState::AwaitingChannelReady(flags)
if flags.clone().clear(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY | FundedStateFlags::PEER_DISCONNECTED | FundedStateFlags::MONITOR_UPDATE_IN_PROGRESS | AwaitingChannelReadyFlags::WAITING_FOR_BATCH).is_empty()
) {
Expand Down Expand Up @@ -13052,22 +13055,22 @@ where

/// Creates a new dual-funded channel from a remote side's request for one.
/// Assumes chain_hash has already been checked and corresponds with what we expect!
/// TODO(dual_funding): Allow contributions, pass intended amount and inputs
#[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled.
#[rustfmt::skip]
pub fn new_inbound<ES: Deref, F: Deref, L: Deref>(
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
holder_node_id: PublicKey, counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
their_features: &InitFeatures, msg: &msgs::OpenChannelV2,
user_id: u128, config: &UserConfig, current_chain_height: u32, logger: &L,
their_features: &InitFeatures, msg: &msgs::OpenChannelV2, user_id: u128, config: &UserConfig,
current_chain_height: u32, logger: &L, our_funding_contribution_sats: u64,
our_funding_inputs: Vec<FundingTxInput>,
) -> Result<Self, ChannelError>
where ES::Target: EntropySource,
F::Target: FeeEstimator,
L::Target: Logger,
{
// TODO(dual_funding): Take these as input once supported
let (our_funding_contribution, our_funding_contribution_sats) = (SignedAmount::ZERO, 0u64);
let our_funding_inputs = Vec::new();
// This u64 -> i64 cast is safe as `our_funding_contribution_sats` is bounded above by the total
// bitcoin supply, which is far less than i64::MAX.
let our_funding_contribution = SignedAmount::from_sat(our_funding_contribution_sats as i64);

let channel_value_satoshis =
our_funding_contribution_sats.saturating_add(msg.common_fields.funding_satoshis);
Expand Down Expand Up @@ -13127,10 +13130,34 @@ where
let inputs_to_contribute = our_funding_inputs
.into_iter()
.map(|FundingTxInput { utxo, sequence, prevtx }| {
(TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() }, prevtx)
(TxIn { previous_output: utxo.outpoint, sequence, ..Default::default() }, prevtx, Weight::from_wu(utxo.satisfaction_weight))
})
.collect();

// Optionally add change output
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this already be covered by begin_interactive_funding_tx_construction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh indeed. begin_interactive_funding_tx_construction was modified to include that in a previous pre-splicing work. Thanks.

let change_script = signer_provider.get_destination_script(context.channel_keys_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe let the user optionally provide a change address along with their inputs?

.map_err(|_| ChannelError::close("Error getting change destination script".to_string()))?;
let change_value_opt = if our_funding_contribution > SignedAmount::ZERO {
calculate_change_output_value(
&funding_negotiation_context, false, &shared_funding_output.script_pubkey, context.holder_dust_limit_satoshis).map_err(|_| ChannelError::close("Error calculating change output value".to_string()))? } else {
None
};
let mut our_funding_outputs = vec![];
if let Some(change_value) = change_value_opt {
let mut change_output = TxOut {
value: Amount::from_sat(change_value),
script_pubkey: change_script,
};
let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
let change_output_fee = fee_for_weight(funding_negotiation_context.funding_feerate_sat_per_1000_weight, change_output_weight);
let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
// Check dust limit again
if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
our_funding_outputs.push(change_output);
}
}

let interactive_tx_constructor = Some(InteractiveTxConstructor::new(
InteractiveTxConstructorArgs {
entropy_source,
Expand All @@ -13143,7 +13170,7 @@ where
inputs_to_contribute,
shared_funding_input: None,
shared_funding_output: SharedOwnedOutput::new(shared_funding_output, our_funding_contribution_sats),
outputs_to_contribute: funding_negotiation_context.our_funding_outputs.clone(),
outputs_to_contribute: our_funding_outputs,
}
).map_err(|err| {
let reason = ClosureReason::ProcessingError { err: err.to_string() };
Expand Down
67 changes: 63 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ use crate::ln::channel::QuiescentAction;
use crate::ln::channel::{
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, FundedChannel,
InboundV1Channel, OutboundV1Channel, PendingV2Channel, ReconnectionMsg, ShutdownResult,
UpdateFulfillCommitFetch, WithChannelContext,
UpdateFulfillCommitFetch, WithChannelContext, TOTAL_BITCOIN_SUPPLY_SATOSHIS,
};
use crate::ln::channel_state::ChannelDetails;
use crate::ln::funding::FundingTxInput;
#[cfg(splicing)]
use crate::ln::funding::SpliceContribution;
use crate::ln::inbound_payment;
Expand Down Expand Up @@ -9154,6 +9155,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
false,
user_channel_id,
config_overrides,
0,
vec![],
)
}

Expand Down Expand Up @@ -9185,15 +9188,71 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
true,
user_channel_id,
config_overrides,
0,
vec![],
)
}

/// Accepts a request to open a dual-funded channel with a contribution provided by us after an
/// [`Event::OpenChannelRequest`].
///
/// The [`Event::OpenChannelRequest::channel_negotiation_type`] field will indicate the open channel
/// request is for a dual-funded channel when the variant is `InboundChannelFunds::DualFunded`.
///
/// The `temporary_channel_id` parameter indicates which inbound channel should be accepted,
/// and the `counterparty_node_id` parameter is the id of the peer which has requested to open
/// the channel.
///
/// The `user_channel_id` parameter will be provided back in
/// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond
/// with which `accept_inbound_channel_*` call.
///
/// The `funding_inputs` parameter provides the `txin`s along with their previous transactions, and
/// a corresponding witness weight for each input that will be used to contribute towards our
/// portion of the channel value. Our contribution will be calculated as the total value of these
/// inputs minus the fees we need to cover for the interactive funding transaction. The witness
/// weights must correspond to the witnesses you will provide through [`ChannelManager::funding_transaction_signed`]
/// after receiving [`Event::FundingTransactionReadyForSigning`].
///
/// Note that this method will return an error and reject the channel if it requires support for
/// zero confirmations.
// TODO(dual_funding): Discussion on complications with 0conf dual-funded channels where "locking"
// of UTXOs used for funding would be required and other issues.
// See https://diyhpl.us/~bryan/irc/bitcoin/bitcoin-dev/linuxfoundation-pipermail/lightning-dev/2023-May/003922.txt
///
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
/// [`Event::OpenChannelRequest::channel_negotiation_type`]: events::Event::OpenChannelRequest::channel_negotiation_type
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
/// [`Event::FundingTransactionReadyForSigning`]: events::Event::FundingTransactionReadyForSigning
/// [`ChannelManager::funding_transaction_signed`]: ChannelManager::funding_transaction_signed
pub fn accept_inbound_channel_with_contribution(
&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey,
user_channel_id: u128, config_overrides: Option<ChannelConfigOverrides>,
our_funding_satoshis: u64, funding_inputs: Vec<FundingTxInput>,
) -> Result<(), APIError> {
self.do_accept_inbound_channel(
temporary_channel_id,
counterparty_node_id,
false,
user_channel_id,
config_overrides,
our_funding_satoshis,
funding_inputs,
)
}

/// TODO(dual_funding): Allow contributions, pass intended amount and inputs
#[rustfmt::skip]
fn do_accept_inbound_channel(
&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool,
user_channel_id: u128, config_overrides: Option<ChannelConfigOverrides>
user_channel_id: u128, config_overrides: Option<ChannelConfigOverrides>, our_funding_satoshis: u64,
funding_inputs: Vec<FundingTxInput>
) -> Result<(), APIError> {
// We do this check early as we will cast this to i64 for the NegotiationContext, and this is the
// actual upper bound which is less than i64::MAX.
if our_funding_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS {
return Err(APIError::APIMisuseError{err: format!("the funding contribution must be smaller than the total bitcoin supply, it was {} satoshis", our_funding_satoshis)});
}

let mut config = self.default_configuration.clone();

Expand Down Expand Up @@ -9251,7 +9310,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
&self.channel_type_features(), &peer_state.latest_features,
&open_channel_msg,
user_channel_id, &config, best_block_height,
&self.logger,
&self.logger, our_funding_satoshis, funding_inputs,
).map_err(|e| {
let channel_id = open_channel_msg.common_fields.temporary_channel_id;
MsgHandleErrInternal::from_chan_no_close(e, channel_id)
Expand Down Expand Up @@ -9534,7 +9593,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
&self.fee_estimator, &self.entropy_source, &self.signer_provider,
self.get_our_node_id(), *counterparty_node_id, &self.channel_type_features(),
&peer_state.latest_features, msg, user_channel_id,
&self.default_configuration, best_block_height, &self.logger,
&self.default_configuration, best_block_height, &self.logger, 0, vec![],
).map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id))?;
let message_send_event = MessageSendEvent::SendAcceptChannelV2 {
node_id: *counterparty_node_id,
Expand Down
Loading
Loading