1010use bitcoin::amount::Amount;
1111use bitcoin::constants::ChainHash;
1212use bitcoin::script::{Script, ScriptBuf, Builder};
13- use bitcoin::transaction::Transaction;
13+ use bitcoin::transaction::{ Transaction, TxIn, TxOut} ;
1414use bitcoin::sighash;
1515use bitcoin::sighash::EcdsaSighashType;
1616use bitcoin::consensus::encode;
17+ use bitcoin::absolute::LockTime;
1718
1819use bitcoin::hashes::Hash;
1920use bitcoin::hashes::sha256::Hash as Sha256;
@@ -28,7 +29,11 @@ use bitcoin::secp256k1;
2829use crate::ln::types::ChannelId;
2930use crate::types::payment::{PaymentPreimage, PaymentHash};
3031use crate::types::features::{ChannelTypeFeatures, InitFeatures};
31- use crate::ln::interactivetxs::InteractiveTxConstructor;
32+ use crate::ln::interactivetxs::{
33+ estimate_input_weight, get_output_weight, HandleTxCompleteResult,
34+ InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSend,
35+ InteractiveTxMessageSendResult, TX_COMMON_FIELDS_WEIGHT,
36+ };
3237use crate::ln::msgs;
3338use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError};
3439use crate::ln::script::{self, ShutdownScript};
@@ -45,14 +50,14 @@ use crate::ln::chan_utils::{
4550use crate::ln::chan_utils;
4651use crate::ln::onion_utils::HTLCFailReason;
4752use crate::chain::BestBlock;
48- use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator};
53+ use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator, fee_for_weight };
4954use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID};
5055use crate::chain::transaction::{OutPoint, TransactionData};
5156use crate::sign::ecdsa::EcdsaChannelSigner;
5257use crate::sign::{EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient};
5358use crate::events::ClosureReason;
5459use crate::routing::gossip::NodeId;
55- use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
60+ use crate::util::ser::{Readable, ReadableArgs, TransactionU16LenLimited, Writeable, Writer};
5661use crate::util::logger::{Logger, Record, WithContext};
5762use crate::util::errors::APIError;
5863use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure};
@@ -1637,6 +1642,109 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for InboundV1Channel<SP> whe
16371642 }
16381643}
16391644
1645+ pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider {
1646+ fn context(&self) -> &ChannelContext<SP>;
1647+
1648+ fn context_mut(&mut self) -> &mut ChannelContext<SP>;
1649+
1650+ fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor>;
1651+
1652+ fn dual_funding_context(&self) -> &DualFundingChannelContext;
1653+
1654+ fn set_interactive_tx_constructor(&mut self, interactive_tx_constructor: InteractiveTxConstructor);
1655+
1656+ fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
1657+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1658+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
1659+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1660+ None => Err(msgs::TxAbort {
1661+ channel_id: self.context().channel_id(),
1662+ data: b"No interactive transaction negotiation in progress".to_vec()
1663+ }),
1664+ })
1665+ }
1666+
1667+ fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
1668+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1669+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
1670+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1671+ None => Err(msgs::TxAbort {
1672+ channel_id: self.context().channel_id(),
1673+ data: b"No interactive transaction negotiation in progress".to_vec()
1674+ }),
1675+ })
1676+ }
1677+
1678+ fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
1679+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1680+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_input(msg).map_err(
1681+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1682+ None => Err(msgs::TxAbort {
1683+ channel_id: self.context().channel_id(),
1684+ data: b"No interactive transaction negotiation in progress".to_vec()
1685+ }),
1686+ })
1687+ }
1688+
1689+ fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
1690+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1691+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_output(msg).map_err(
1692+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1693+ None => Err(msgs::TxAbort {
1694+ channel_id: self.context().channel_id(),
1695+ data: b"No interactive transaction negotiation in progress".to_vec()
1696+ }),
1697+ })
1698+ }
1699+
1700+ fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
1701+ HandleTxCompleteResult(match self.interactive_tx_constructor_mut() {
1702+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_complete(msg).map_err(
1703+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1704+ None => Err(msgs::TxAbort {
1705+ channel_id: self.context().channel_id(),
1706+ data: b"No interactive transaction negotiation in progress".to_vec()
1707+ }),
1708+ })
1709+ }
1710+ }
1711+
1712+ impl<SP: Deref> InteractivelyFunded<SP> for OutboundV2Channel<SP> where SP::Target: SignerProvider {
1713+ fn context(&self) -> &ChannelContext<SP> {
1714+ &self.context
1715+ }
1716+ fn context_mut(&mut self) -> &mut ChannelContext<SP> {
1717+ &mut self.context
1718+ }
1719+ fn dual_funding_context(&self) -> &DualFundingChannelContext {
1720+ &self.dual_funding_context
1721+ }
1722+ fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor> {
1723+ &mut self.interactive_tx_constructor
1724+ }
1725+ fn set_interactive_tx_constructor(&mut self, interactive_tx_constructor: InteractiveTxConstructor) {
1726+ self.interactive_tx_constructor = Some(interactive_tx_constructor);
1727+ }
1728+ }
1729+
1730+ impl<SP: Deref> InteractivelyFunded<SP> for InboundV2Channel<SP> where SP::Target: SignerProvider {
1731+ fn context(&self) -> &ChannelContext<SP> {
1732+ &self.context
1733+ }
1734+ fn context_mut(&mut self) -> &mut ChannelContext<SP> {
1735+ &mut self.context
1736+ }
1737+ fn dual_funding_context(&self) -> &DualFundingChannelContext {
1738+ &self.dual_funding_context
1739+ }
1740+ fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor> {
1741+ &mut self.interactive_tx_constructor
1742+ }
1743+ fn set_interactive_tx_constructor(&mut self, interactive_tx_constructor: InteractiveTxConstructor) {
1744+ self.interactive_tx_constructor = Some(interactive_tx_constructor);
1745+ }
1746+ }
1747+
16401748impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
16411749 fn new_for_inbound_channel<'a, ES: Deref, F: Deref, L: Deref>(
16421750 fee_estimator: &'a LowerBoundedFeeEstimator<F>,
@@ -3766,6 +3874,16 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
37663874 self.channel_transaction_parameters.channel_type_features = self.channel_type.clone();
37673875 Ok(())
37683876 }
3877+
3878+ // Interactive transaction construction
3879+
3880+ pub fn tx_signatures(&self, msg: &msgs::TxSignatures) -> Result<InteractiveTxMessageSend, ChannelError> {
3881+ todo!();
3882+ }
3883+
3884+ pub fn tx_abort(&self, msg: &msgs::TxAbort) -> Result<InteractiveTxMessageSend, ChannelError> {
3885+ todo!();
3886+ }
37693887}
37703888
37713889// Internal utility functions for channels
@@ -3823,6 +3941,42 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
38233941 cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis))
38243942}
38253943
3944+ pub(super) fn calculate_our_funding_satoshis(
3945+ is_initiator: bool, funding_inputs: &[(TxIn, TransactionU16LenLimited)],
3946+ funding_outputs: &[TxOut], funding_feerate_sat_per_1000_weight: u32,
3947+ holder_dust_limit_satoshis: u64,
3948+ ) -> Result<u64, APIError> {
3949+ let mut total_input_satoshis = 0u64;
3950+ let mut our_contributed_weight = 0u64;
3951+
3952+ for (idx, input) in funding_inputs.iter().enumerate() {
3953+ if let Some(output) = input.1.as_transaction().output.get(input.0.previous_output.vout as usize) {
3954+ total_input_satoshis = total_input_satoshis.saturating_add(output.value.to_sat());
3955+ our_contributed_weight = our_contributed_weight.saturating_add(estimate_input_weight(output).to_wu());
3956+ } else {
3957+ return Err(APIError::APIMisuseError {
3958+ err: format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
3959+ input.1.as_transaction().compute_txid(), input.0.previous_output.vout, idx) });
3960+ }
3961+ }
3962+ our_contributed_weight = our_contributed_weight.saturating_add(funding_outputs.iter().fold(0u64, |weight, txout| {
3963+ weight.saturating_add(get_output_weight(&txout.script_pubkey).to_wu())
3964+ }));
3965+
3966+ // If we are the initiator, we must pay for weight of all common fields in the funding transaction.
3967+ if is_initiator {
3968+ our_contributed_weight = our_contributed_weight.saturating_add(TX_COMMON_FIELDS_WEIGHT);
3969+ }
3970+
3971+ let funding_satoshis = total_input_satoshis
3972+ .saturating_sub(fee_for_weight(funding_feerate_sat_per_1000_weight, our_contributed_weight));
3973+ if funding_satoshis < holder_dust_limit_satoshis {
3974+ Ok(0)
3975+ } else {
3976+ Ok(funding_satoshis)
3977+ }
3978+ }
3979+
38263980/// Context for dual-funded channels.
38273981pub(super) struct DualFundingChannelContext {
38283982 /// The amount in satoshis we will be contributing to the channel.
@@ -3831,9 +3985,15 @@ pub(super) struct DualFundingChannelContext {
38313985 pub their_funding_satoshis: u64,
38323986 /// The funding transaction locktime suggested by the initiator. If set by us, it is always set
38333987 /// to the current block height to align incentives against fee-sniping.
3834- pub funding_tx_locktime: u32 ,
3988+ pub funding_tx_locktime: LockTime ,
38353989 /// The feerate set by the initiator to be used for the funding transaction.
38363990 pub funding_feerate_sat_per_1000_weight: u32,
3991+ /// The funding inputs we will be contributing to the channel.
3992+ ///
3993+ /// Note that the `our_funding_satoshis` field is equal to the total value of `our_funding_inputs`
3994+ /// minus any fees paid for our contributed weight. This means that change will never be generated
3995+ /// and the maximum value possible will go towards funding the channel.
3996+ pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
38373997}
38383998
38393999// Holder designates channel data owned for the benefit of the user client.
@@ -8264,8 +8424,9 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
82648424 pub fn new<ES: Deref, F: Deref, L: Deref>(
82658425 fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
82668426 counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
8267- user_id: u128, config: &UserConfig, current_chain_height: u32, outbound_scid_alias: u64,
8268- funding_confirmation_target: ConfirmationTarget, logger: L,
8427+ funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, user_id: u128, config: &UserConfig,
8428+ current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
8429+ logger: L,
82698430 ) -> Result<OutboundV2Channel<SP>, APIError>
82708431 where ES::Target: EntropySource,
82718432 F::Target: FeeEstimator,
@@ -8281,7 +8442,11 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
82818442 funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
82828443
82838444 let funding_feerate_sat_per_1000_weight = fee_estimator.bounded_sat_per_1000_weight(funding_confirmation_target);
8284- let funding_tx_locktime = current_chain_height;
8445+ let funding_tx_locktime = LockTime::from_height(current_chain_height)
8446+ .map_err(|_| APIError::APIMisuseError {
8447+ err: format!(
8448+ "Provided current chain height of {} doesn't make sense for a height-based timelock for the funding transaction",
8449+ current_chain_height) })?;
82858450
82868451 let chan = Self {
82878452 context: ChannelContext::new_for_outbound_channel(
@@ -8309,6 +8474,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
83098474 their_funding_satoshis: 0,
83108475 funding_tx_locktime,
83118476 funding_feerate_sat_per_1000_weight,
8477+ our_funding_inputs: funding_inputs,
83128478 },
83138479 interactive_tx_constructor: None,
83148480 };
@@ -8373,7 +8539,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
83738539 },
83748540 funding_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
83758541 second_per_commitment_point,
8376- locktime: self.dual_funding_context.funding_tx_locktime,
8542+ locktime: self.dual_funding_context.funding_tx_locktime.to_consensus_u32() ,
83778543 require_confirmed_inputs: None,
83788544 }
83798545 }
@@ -8394,13 +8560,22 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
83948560 pub fn new<ES: Deref, F: Deref, L: Deref>(
83958561 fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
83968562 counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
8397- their_features: &InitFeatures, msg: &msgs::OpenChannelV2, funding_satoshis: u64, user_id: u128,
8398- config: &UserConfig, current_chain_height: u32, logger: &L,
8563+ their_features: &InitFeatures, msg: &msgs::OpenChannelV2,
8564+ funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, user_id: u128, config: &UserConfig,
8565+ current_chain_height: u32, logger: &L,
83998566 ) -> Result<InboundV2Channel<SP>, ChannelError>
84008567 where ES::Target: EntropySource,
84018568 F::Target: FeeEstimator,
84028569 L::Target: Logger,
84038570 {
8571+ let funding_satoshis = calculate_our_funding_satoshis(
8572+ false, &funding_inputs, &[], msg.funding_feerate_sat_per_1000_weight,
8573+ msg.common_fields.dust_limit_satoshis
8574+ ).map_err(|_| ChannelError::Close(
8575+ (
8576+ "Failed to accept channel".to_string(),
8577+ ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8578+ )))?;
84048579 let channel_value_satoshis = funding_satoshis.saturating_add(msg.common_fields.funding_satoshis);
84058580 let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
84068581 channel_value_satoshis, msg.common_fields.dust_limit_satoshis);
@@ -8449,19 +8624,43 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
84498624 &context.get_counterparty_pubkeys().revocation_basepoint);
84508625 context.channel_id = channel_id;
84518626
8452- let chan = Self {
8627+ let mut channel = Self {
84538628 context,
84548629 unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
84558630 dual_funding_context: DualFundingChannelContext {
84568631 our_funding_satoshis: funding_satoshis,
84578632 their_funding_satoshis: msg.common_fields.funding_satoshis,
8458- funding_tx_locktime: msg.locktime,
8633+ funding_tx_locktime: LockTime::from_consensus( msg.locktime) ,
84598634 funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
8635+ our_funding_inputs: funding_inputs,
84608636 },
84618637 interactive_tx_constructor: None,
84628638 };
84638639
8464- Ok(chan)
8640+ match InteractiveTxConstructor::new(
8641+ InteractiveTxConstructorArgs {
8642+ entropy_source,
8643+ channel_id: channel.context.channel_id,
8644+ feerate_sat_per_kw: channel.dual_funding_context.funding_feerate_sat_per_1000_weight,
8645+ funding_tx_locktime: channel.dual_funding_context.funding_tx_locktime,
8646+ is_initiator: false,
8647+ inputs_to_contribute: channel.dual_funding_context.our_funding_inputs.clone(),
8648+ outputs_to_contribute: Vec::new(),
8649+ expected_remote_shared_funding_output: Some((channel.context().get_funding_redeemscript(), channel.context().channel_value_satoshis)),
8650+ }
8651+ ) {
8652+ Ok(tx_constructor) => {
8653+ channel.set_interactive_tx_constructor(tx_constructor);
8654+ },
8655+ Err(_) => {
8656+ return Err(ChannelError::Close((
8657+ "V2 channel rejected due to sender error".into(),
8658+ ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8659+ )))
8660+ }
8661+ }
8662+
8663+ Ok(channel)
84658664 }
84668665
84678666 /// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannelV2`] message which
0 commit comments