Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 480
Dual funding extension: begin_interactive_funding_tx_construction#3443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -10,7 +10,7 @@ | ||
| use bitcoin::amount::Amount; | ||
| use bitcoin::constants::ChainHash; | ||
| use bitcoin::script::{Script, ScriptBuf, Builder, WScriptHash}; | ||
| use bitcoin::transaction::{Transaction, TxIn}; | ||
| use bitcoin::transaction::{Transaction, TxIn, TxOut}; | ||
| use bitcoin::sighash::EcdsaSighashType; | ||
| use bitcoin::consensus::encode; | ||
| use bitcoin::absolute::LockTime; | ||
| @@ -30,9 +30,9 @@ use crate::ln::types::ChannelId; | ||
| use crate::types::payment::{PaymentPreimage, PaymentHash}; | ||
| use crate::types::features::{ChannelTypeFeatures, InitFeatures}; | ||
| use crate::ln::interactivetxs::{ | ||
| get_output_weight, HandleTxCompleteValue, HandleTxCompleteResult, InteractiveTxConstructor, | ||
| InteractiveTxConstructorArgs, InteractiveTxSigningSession, InteractiveTxMessageSendResult, | ||
| TX_COMMON_FIELDS_WEIGHT, | ||
| calculate_change_output_value, get_output_weight, AbortReason, HandleTxCompleteValue, HandleTxCompleteResult, InteractiveTxConstructor, | ||
| InteractiveTxConstructorArgs, InteractiveTxMessageSend, InteractiveTxSigningSession, InteractiveTxMessageSendResult, | ||
| OutputOwned, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT, | ||
| }; | ||
| use crate::ln::msgs; | ||
| use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket}; | ||
| @@ -2220,6 +2220,95 @@ impl<SP: Deref> InitialRemoteCommitmentReceiver<SP> for FundedChannel<SP> where | ||
| } | ||
| impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider { | ||
| /// Prepare and start interactive transaction negotiation. | ||
| /// `change_destination_opt` - Optional destination for optional change; if None, | ||
| /// default destination address is used. | ||
| /// If error occurs, it is caused by our side, not the counterparty. | ||
| #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled | ||
| fn begin_interactive_funding_tx_construction<ES: Deref>( | ||
| &mut self, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, | ||
| change_destination_opt: Option<ScriptBuf>, | ||
| ) -> Result<Option<InteractiveTxMessageSend>, AbortReason> | ||
| where ES::Target: EntropySource | ||
| { | ||
| debug_assert!(matches!(self.context.channel_state, ChannelState::NegotiatingFunding(_))); | ||
| debug_assert!(self.interactive_tx_constructor.is_none()); | ||
optout21 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| let mut funding_inputs = Vec::new(); | ||
| mem::swap(&mut self.dual_funding_context.our_funding_inputs, &mut funding_inputs); | ||
| // TODO(splicing): Add prev funding tx as input, must be provided as a parameter | ||
| // Add output for funding tx | ||
| // Note: For the error case when the inputs are insufficient, it will be handled after | ||
| // the `calculate_change_output_value` call below | ||
| let mut funding_outputs = Vec::new(); | ||
optout21 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| let mut expected_remote_shared_funding_output = None; | ||
| let shared_funding_output = TxOut { | ||
| value: Amount::from_sat(self.funding.get_value_satoshis()), | ||
| script_pubkey: self.funding.get_funding_redeemscript().to_p2wsh(), | ||
| }; | ||
| if self.funding.is_outbound() { | ||
| funding_outputs.push( | ||
optout21 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| OutputOwned::Shared(SharedOwnedOutput::new( | ||
| shared_funding_output, self.dual_funding_context.our_funding_satoshis, | ||
| )) | ||
| ); | ||
| } else { | ||
| let TxOut { value, script_pubkey } = shared_funding_output; | ||
| expected_remote_shared_funding_output = Some((script_pubkey, value.to_sat())); | ||
| } | ||
| // Optionally add change output | ||
| let change_script = if let Some(script) = change_destination_opt { | ||
| script | ||
| } else { | ||
| signer_provider.get_destination_script(self.context.channel_keys_id) | ||
| .map_err(|_err| AbortReason::InternalError("Error getting destination script"))? | ||
| }; | ||
| let change_value_opt = calculate_change_output_value( | ||
| self.funding.is_outbound(), self.dual_funding_context.our_funding_satoshis, | ||
| &funding_inputs, &funding_outputs, | ||
| self.dual_funding_context.funding_feerate_sat_per_1000_weight, | ||
| change_script.minimal_non_dust().to_sat(), | ||
| )?; | ||
| 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(self.dual_funding_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 > self.context.holder_dust_limit_satoshis { | ||
optout21 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| change_output.value = Amount::from_sat(change_value_decreased_with_fee); | ||
| funding_outputs.push(OutputOwned::Single(change_output)); | ||
| } | ||
| } | ||
| let constructor_args = InteractiveTxConstructorArgs { | ||
| entropy_source, | ||
| holder_node_id, | ||
| counterparty_node_id: self.context.counterparty_node_id, | ||
| channel_id: self.context.channel_id(), | ||
| feerate_sat_per_kw: self.dual_funding_context.funding_feerate_sat_per_1000_weight, | ||
| is_initiator: self.funding.is_outbound(), | ||
| funding_tx_locktime: self.dual_funding_context.funding_tx_locktime, | ||
| inputs_to_contribute: funding_inputs, | ||
optout21 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| outputs_to_contribute: funding_outputs, | ||
| expected_remote_shared_funding_output, | ||
| }; | ||
| let mut tx_constructor = InteractiveTxConstructor::new(constructor_args)?; | ||
| let msg = tx_constructor.take_initiator_first_message(); | ||
| self.interactive_tx_constructor = Some(tx_constructor); | ||
| Ok(msg) | ||
| } | ||
| pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult { | ||
| InteractiveTxMessageSendResult(match &mut self.interactive_tx_constructor { | ||
| Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err( | ||
| @@ -4849,6 +4938,9 @@ fn check_v2_funding_inputs_sufficient( | ||
| pub(super) struct DualFundingChannelContext { | ||
| /// The amount in satoshis we will be contributing to the channel. | ||
| pub our_funding_satoshis: u64, | ||
| /// The amount in satoshis our counterparty will be contributing to the channel. | ||
| #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled. | ||
| pub their_funding_satoshis: Option<u64>, | ||
| /// The funding transaction locktime suggested by the initiator. If set by us, it is always set | ||
| /// to the current block height to align incentives against fee-sniping. | ||
| pub funding_tx_locktime: LockTime, | ||
| @@ -4860,6 +4952,8 @@ pub(super) struct DualFundingChannelContext { | ||
| /// Note that the `our_funding_satoshis` field is equal to the total value of `our_funding_inputs` | ||
| /// minus any fees paid for our contributed weight. This means that change will never be generated | ||
| /// and the maximum value possible will go towards funding the channel. | ||
| /// | ||
| /// Note that this field may be emptied once the interactive negotiation has been started. | ||
| #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled. | ||
| pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, | ||
| } | ||
| @@ -9829,16 +9923,19 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider { | ||
| unfunded_channel_age_ticks: 0, | ||
| holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx), | ||
| }; | ||
| let dual_funding_context = DualFundingChannelContext { | ||
| our_funding_satoshis: funding_satoshis, | ||
| // TODO(dual_funding) TODO(splicing) Include counterparty contribution, once that's enabled | ||
| their_funding_satoshis: None, | ||
optout21 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| funding_tx_locktime, | ||
| funding_feerate_sat_per_1000_weight, | ||
| our_funding_inputs: funding_inputs, | ||
| }; | ||
| let chan = Self { | ||
| funding, | ||
| context, | ||
| unfunded_context, | ||
| dual_funding_context: DualFundingChannelContext { | ||
| our_funding_satoshis: funding_satoshis, | ||
| funding_tx_locktime, | ||
| funding_feerate_sat_per_1000_weight, | ||
| our_funding_inputs: funding_inputs, | ||
| }, | ||
| dual_funding_context, | ||
| interactive_tx_constructor: None, | ||
| interactive_tx_signing_session: None, | ||
| }; | ||
| @@ -9980,6 +10077,7 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider { | ||
| let dual_funding_context = DualFundingChannelContext { | ||
| our_funding_satoshis: our_funding_satoshis, | ||
| their_funding_satoshis: Some(msg.common_fields.funding_satoshis), | ||
| funding_tx_locktime: LockTime::from_consensus(msg.locktime), | ||
| funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight, | ||
| our_funding_inputs: our_funding_inputs.clone(), | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.