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;
@@ -27,7 +28,11 @@ use bitcoin::secp256k1;
2728
2829use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash};
2930use crate::ln::features::{ChannelTypeFeatures, InitFeatures};
30- use crate::ln::interactivetxs::InteractiveTxConstructor;
31+ use crate::ln::interactivetxs::{
32+ estimate_input_weight, get_output_weight, HandleTxCompleteResult,
33+ InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSend,
34+ InteractiveTxMessageSendResult, TX_COMMON_FIELDS_WEIGHT,
35+ };
3136use crate::ln::msgs;
3237use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError};
3338use crate::ln::script::{self, ShutdownScript};
@@ -44,14 +49,14 @@ use crate::ln::chan_utils::{
4449use crate::ln::chan_utils;
4550use crate::ln::onion_utils::HTLCFailReason;
4651use crate::chain::BestBlock;
47- use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator};
52+ use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator, fee_for_weight };
4853use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS, CLOSED_CHANNEL_UPDATE_ID};
4954use crate::chain::transaction::{OutPoint, TransactionData};
5055use crate::sign::ecdsa::EcdsaChannelSigner;
5156use crate::sign::{EntropySource, ChannelSigner, SignerProvider, NodeSigner, Recipient};
5257use crate::events::ClosureReason;
5358use crate::routing::gossip::NodeId;
54- use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer};
59+ use crate::util::ser::{Readable, ReadableArgs, TransactionU16LenLimited, Writeable, Writer};
5560use crate::util::logger::{Logger, Record, WithContext};
5661use crate::util::errors::APIError;
5762use crate::util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits, MaxDustHTLCExposure};
@@ -1489,6 +1494,109 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
14891494 blocked_monitor_updates: Vec<PendingChannelMonitorUpdate>,
14901495}
14911496
1497+ pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider {
1498+ fn context(&self) -> &ChannelContext<SP>;
1499+
1500+ fn context_mut(&mut self) -> &mut ChannelContext<SP>;
1501+
1502+ fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor>;
1503+
1504+ fn dual_funding_context(&self) -> &DualFundingChannelContext;
1505+
1506+ fn set_interactive_tx_constructor(&mut self, interactive_tx_constructor: InteractiveTxConstructor);
1507+
1508+ fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
1509+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1510+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
1511+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1512+ None => Err(msgs::TxAbort {
1513+ channel_id: self.context().channel_id(),
1514+ data: b"No interactive transaction negotiation in progress".to_vec()
1515+ }),
1516+ })
1517+ }
1518+
1519+ fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
1520+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1521+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
1522+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1523+ None => Err(msgs::TxAbort {
1524+ channel_id: self.context().channel_id(),
1525+ data: b"No interactive transaction negotiation in progress".to_vec()
1526+ }),
1527+ })
1528+ }
1529+
1530+ fn tx_remove_input(&mut self, msg: &msgs::TxRemoveInput)-> InteractiveTxMessageSendResult {
1531+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1532+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_input(msg).map_err(
1533+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1534+ None => Err(msgs::TxAbort {
1535+ channel_id: self.context().channel_id(),
1536+ data: b"No interactive transaction negotiation in progress".to_vec()
1537+ }),
1538+ })
1539+ }
1540+
1541+ fn tx_remove_output(&mut self, msg: &msgs::TxRemoveOutput)-> InteractiveTxMessageSendResult {
1542+ InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
1543+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_remove_output(msg).map_err(
1544+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1545+ None => Err(msgs::TxAbort {
1546+ channel_id: self.context().channel_id(),
1547+ data: b"No interactive transaction negotiation in progress".to_vec()
1548+ }),
1549+ })
1550+ }
1551+
1552+ fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
1553+ HandleTxCompleteResult(match self.interactive_tx_constructor_mut() {
1554+ Some(ref mut tx_constructor) => tx_constructor.handle_tx_complete(msg).map_err(
1555+ |reason| reason.into_tx_abort_msg(self.context().channel_id())),
1556+ None => Err(msgs::TxAbort {
1557+ channel_id: self.context().channel_id(),
1558+ data: b"No interactive transaction negotiation in progress".to_vec()
1559+ }),
1560+ })
1561+ }
1562+ }
1563+
1564+ impl<SP: Deref> InteractivelyFunded<SP> for OutboundV2Channel<SP> where SP::Target: SignerProvider {
1565+ fn context(&self) -> &ChannelContext<SP> {
1566+ &self.context
1567+ }
1568+ fn context_mut(&mut self) -> &mut ChannelContext<SP> {
1569+ &mut self.context
1570+ }
1571+ fn dual_funding_context(&self) -> &DualFundingChannelContext {
1572+ &self.dual_funding_context
1573+ }
1574+ fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor> {
1575+ &mut self.interactive_tx_constructor
1576+ }
1577+ fn set_interactive_tx_constructor(&mut self, interactive_tx_constructor: InteractiveTxConstructor) {
1578+ self.interactive_tx_constructor = Some(interactive_tx_constructor);
1579+ }
1580+ }
1581+
1582+ impl<SP: Deref> InteractivelyFunded<SP> for InboundV2Channel<SP> where SP::Target: SignerProvider {
1583+ fn context(&self) -> &ChannelContext<SP> {
1584+ &self.context
1585+ }
1586+ fn context_mut(&mut self) -> &mut ChannelContext<SP> {
1587+ &mut self.context
1588+ }
1589+ fn dual_funding_context(&self) -> &DualFundingChannelContext {
1590+ &self.dual_funding_context
1591+ }
1592+ fn interactive_tx_constructor_mut(&mut self) -> &mut Option<InteractiveTxConstructor> {
1593+ &mut self.interactive_tx_constructor
1594+ }
1595+ fn set_interactive_tx_constructor(&mut self, interactive_tx_constructor: InteractiveTxConstructor) {
1596+ self.interactive_tx_constructor = Some(interactive_tx_constructor);
1597+ }
1598+ }
1599+
14921600impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
14931601 fn new_for_inbound_channel<'a, ES: Deref, F: Deref, L: Deref>(
14941602 fee_estimator: &'a LowerBoundedFeeEstimator<F>,
@@ -3616,6 +3724,16 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
36163724 self.channel_transaction_parameters.channel_type_features = self.channel_type.clone();
36173725 Ok(())
36183726 }
3727+
3728+ // Interactive transaction construction
3729+
3730+ pub fn tx_signatures(&self, msg: &msgs::TxSignatures) -> Result<InteractiveTxMessageSend, ChannelError> {
3731+ todo!();
3732+ }
3733+
3734+ pub fn tx_abort(&self, msg: &msgs::TxAbort) -> Result<InteractiveTxMessageSend, ChannelError> {
3735+ todo!();
3736+ }
36193737}
36203738
36213739// Internal utility functions for channels
@@ -3673,6 +3791,42 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
36733791 cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis))
36743792}
36753793
3794+ pub(super) fn calculate_our_funding_satoshis(
3795+ is_initiator: bool, funding_inputs: &[(TxIn, TransactionU16LenLimited)],
3796+ funding_outputs: &[TxOut], funding_feerate_sat_per_1000_weight: u32,
3797+ holder_dust_limit_satoshis: u64,
3798+ ) -> Result<u64, APIError> {
3799+ let mut total_input_satoshis = 0u64;
3800+ let mut our_contributed_weight = 0u64;
3801+
3802+ for (idx, input) in funding_inputs.iter().enumerate() {
3803+ if let Some(output) = input.1.as_transaction().output.get(input.0.previous_output.vout as usize) {
3804+ total_input_satoshis = total_input_satoshis.saturating_add(output.value.to_sat());
3805+ our_contributed_weight = our_contributed_weight.saturating_add(estimate_input_weight(output).to_wu());
3806+ } else {
3807+ return Err(APIError::APIMisuseError {
3808+ err: format!("Transaction with txid {} does not have an output with vout of {} corresponding to TxIn at funding_inputs[{}]",
3809+ input.1.as_transaction().compute_txid(), input.0.previous_output.vout, idx) });
3810+ }
3811+ }
3812+ our_contributed_weight = our_contributed_weight.saturating_add(funding_outputs.iter().fold(0u64, |weight, txout| {
3813+ weight.saturating_add(get_output_weight(&txout.script_pubkey).to_wu())
3814+ }));
3815+
3816+ // If we are the initiator, we must pay for weight of all common fields in the funding transaction.
3817+ if is_initiator {
3818+ our_contributed_weight = our_contributed_weight.saturating_add(TX_COMMON_FIELDS_WEIGHT);
3819+ }
3820+
3821+ let funding_satoshis = total_input_satoshis
3822+ .saturating_sub(fee_for_weight(funding_feerate_sat_per_1000_weight, our_contributed_weight));
3823+ if funding_satoshis < holder_dust_limit_satoshis {
3824+ Ok(0)
3825+ } else {
3826+ Ok(funding_satoshis)
3827+ }
3828+ }
3829+
36763830/// Context for dual-funded channels.
36773831pub(super) struct DualFundingChannelContext {
36783832 /// The amount in satoshis we will be contributing to the channel.
@@ -3681,9 +3835,15 @@ pub(super) struct DualFundingChannelContext {
36813835 pub their_funding_satoshis: u64,
36823836 /// The funding transaction locktime suggested by the initiator. If set by us, it is always set
36833837 /// to the current block height to align incentives against fee-sniping.
3684- pub funding_tx_locktime: u32 ,
3838+ pub funding_tx_locktime: LockTime ,
36853839 /// The feerate set by the initiator to be used for the funding transaction.
36863840 pub funding_feerate_sat_per_1000_weight: u32,
3841+ /// The funding inputs we will be contributing to the channel.
3842+ ///
3843+ /// Note that the `our_funding_satoshis` field is equal to the total value of `our_funding_inputs`
3844+ /// minus any fees paid for our contributed weight. This means that change will never be generated
3845+ /// and the maximum value possible will go towards funding the channel.
3846+ pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
36873847}
36883848
36893849// Holder designates channel data owned for the benefit of the user client.
@@ -8244,8 +8404,9 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
82448404 pub fn new<ES: Deref, F: Deref, L: Deref>(
82458405 fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
82468406 counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
8247- user_id: u128, config: &UserConfig, current_chain_height: u32, outbound_scid_alias: u64,
8248- funding_confirmation_target: ConfirmationTarget, logger: L,
8407+ funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, user_id: u128, config: &UserConfig,
8408+ current_chain_height: u32, outbound_scid_alias: u64, funding_confirmation_target: ConfirmationTarget,
8409+ logger: L,
82498410 ) -> Result<OutboundV2Channel<SP>, APIError>
82508411 where ES::Target: EntropySource,
82518412 F::Target: FeeEstimator,
@@ -8261,7 +8422,11 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
82618422 funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
82628423
82638424 let funding_feerate_sat_per_1000_weight = fee_estimator.bounded_sat_per_1000_weight(funding_confirmation_target);
8264- let funding_tx_locktime = current_chain_height;
8425+ let funding_tx_locktime = LockTime::from_height(current_chain_height)
8426+ .map_err(|_| APIError::APIMisuseError {
8427+ err: format!(
8428+ "Provided current chain height of {} doesn't make sense for a height-based timelock for the funding transaction",
8429+ current_chain_height) })?;
82658430
82668431 let chan = Self {
82678432 context: ChannelContext::new_for_outbound_channel(
@@ -8289,6 +8454,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
82898454 their_funding_satoshis: 0,
82908455 funding_tx_locktime,
82918456 funding_feerate_sat_per_1000_weight,
8457+ our_funding_inputs: funding_inputs,
82928458 },
82938459 interactive_tx_constructor: None,
82948460 };
@@ -8353,7 +8519,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
83538519 },
83548520 funding_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
83558521 second_per_commitment_point,
8356- locktime: self.dual_funding_context.funding_tx_locktime,
8522+ locktime: self.dual_funding_context.funding_tx_locktime.to_consensus_u32() ,
83578523 require_confirmed_inputs: None,
83588524 }
83598525 }
@@ -8374,13 +8540,22 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
83748540 pub fn new<ES: Deref, F: Deref, L: Deref>(
83758541 fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
83768542 counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
8377- their_features: &InitFeatures, msg: &msgs::OpenChannelV2, funding_satoshis: u64, user_id: u128,
8378- config: &UserConfig, current_chain_height: u32, logger: &L,
8543+ their_features: &InitFeatures, msg: &msgs::OpenChannelV2,
8544+ funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, user_id: u128, config: &UserConfig,
8545+ current_chain_height: u32, logger: &L,
83798546 ) -> Result<InboundV2Channel<SP>, ChannelError>
83808547 where ES::Target: EntropySource,
83818548 F::Target: FeeEstimator,
83828549 L::Target: Logger,
83838550 {
8551+ let funding_satoshis = calculate_our_funding_satoshis(
8552+ false, &funding_inputs, &[], msg.funding_feerate_sat_per_1000_weight,
8553+ msg.common_fields.dust_limit_satoshis
8554+ ).map_err(|_| ChannelError::Close(
8555+ (
8556+ "Failed to accept channel".to_string(),
8557+ ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8558+ )))?;
83848559 let channel_value_satoshis = funding_satoshis.saturating_add(msg.common_fields.funding_satoshis);
83858560 let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
83868561 channel_value_satoshis, msg.common_fields.dust_limit_satoshis);
@@ -8429,19 +8604,43 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
84298604 &context.get_counterparty_pubkeys().revocation_basepoint);
84308605 context.channel_id = channel_id;
84318606
8432- let chan = Self {
8607+ let mut channel = Self {
84338608 context,
84348609 unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
84358610 dual_funding_context: DualFundingChannelContext {
84368611 our_funding_satoshis: funding_satoshis,
84378612 their_funding_satoshis: msg.common_fields.funding_satoshis,
8438- funding_tx_locktime: msg.locktime,
8613+ funding_tx_locktime: LockTime::from_consensus( msg.locktime) ,
84398614 funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
8615+ our_funding_inputs: funding_inputs,
84408616 },
84418617 interactive_tx_constructor: None,
84428618 };
84438619
8444- Ok(chan)
8620+ match InteractiveTxConstructor::new(
8621+ InteractiveTxConstructorArgs {
8622+ entropy_source,
8623+ channel_id: channel.context.channel_id,
8624+ feerate_sat_per_kw: channel.dual_funding_context.funding_feerate_sat_per_1000_weight,
8625+ funding_tx_locktime: channel.dual_funding_context.funding_tx_locktime,
8626+ is_initiator: false,
8627+ inputs_to_contribute: channel.dual_funding_context.our_funding_inputs.clone(),
8628+ outputs_to_contribute: Vec::new(),
8629+ expected_remote_shared_funding_output: Some((channel.context().get_funding_redeemscript(), channel.context().channel_value_satoshis)),
8630+ }
8631+ ) {
8632+ Ok(tx_constructor) => {
8633+ channel.set_interactive_tx_constructor(tx_constructor);
8634+ },
8635+ Err(_) => {
8636+ return Err(ChannelError::Close((
8637+ "V2 channel rejected due to sender error".into(),
8638+ ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8639+ )))
8640+ }
8641+ }
8642+
8643+ Ok(channel)
84458644 }
84468645
84478646 /// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannelV2`] message which
0 commit comments