Skip to content

Commit cb1c7f3

Browse files
committed
Handle initial commitment_signed for V2 channels
1 parent a5306b3 commit cb1c7f3

File tree

3 files changed

+377
-150
lines changed

3 files changed

+377
-150
lines changed

lightning/src/ln/channel.rs

Lines changed: 225 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ use bitcoin::locktime::absolute::LockTime;
2929
use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash};
3030
use crate::ln::features::{ChannelTypeFeatures, InitFeatures};
3131
use crate::ln::interactivetxs::{
32-
AbortReason, estimate_input_weight, get_output_weight, HandleTxCompleteResult,
33-
InteractiveTxConstructor, InteractiveTxMessageSend, InteractiveTxMessageSendResult,
34-
OutputOwned, TX_COMMON_FIELDS_WEIGHT,
32+
AbortReason, ConstructedTransaction, estimate_input_weight, get_output_weight,
33+
HandleTxCompleteResult, InteractiveTxConstructor, InteractiveTxMessageSend,
34+
InteractiveTxMessageSendResult, OutputOwned, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
3535
};
3636
use crate::ln::msgs;
3737
use crate::ln::msgs::DecodeError;
@@ -64,7 +64,6 @@ use crate::sync::Mutex;
6464
use crate::sign::type_resolver::ChannelSignerType;
6565

6666
use super::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint};
67-
use super::interactivetxs::SharedOwnedOutput;
6867

6968
#[cfg(test)]
7069
pub struct ChannelValueStat {
@@ -1463,7 +1462,7 @@ pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider
14631462
script_pubkey: self.context().get_funding_redeemscript().to_p2wsh(),
14641463
};
14651464
funding_outputs.push(
1466-
if self.dual_funding_context_mut().their_funding_satoshis > 0 {
1465+
if self.dual_funding_context_mut().their_funding_satoshis.unwrap_or(0) > 0 {
14671466
OutputOwned::Shared(SharedOwnedOutput::new(tx_out, self.dual_funding_context_mut().our_funding_satoshis))
14681467
} else {
14691468
OutputOwned::SharedControlFullyOwned(tx_out)
@@ -3822,7 +3821,7 @@ pub(super) struct DualFundingChannelContext {
38223821
/// The amount in satoshis we will be contributing to the channel.
38233822
pub our_funding_satoshis: u64,
38243823
/// The amount in satoshis our counterparty will be contributing to the channel.
3825-
pub their_funding_satoshis: u64,
3824+
pub their_funding_satoshis: Option<u64>,
38263825
/// The funding transaction locktime suggested by the initiator. If set by us, it is always set
38273826
/// to the current block height to align incentives against fee-sniping.
38283827
pub funding_tx_locktime: LockTime,
@@ -4613,6 +4612,102 @@ impl<SP: Deref> Channel<SP> where
46134612
Ok(())
46144613
}
46154614

4615+
pub fn commitment_signed_initial_v2<L: Deref>(
4616+
&mut self, msg: &msgs::CommitmentSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
4617+
) -> Result<ChannelMonitor<<SP::Target as SignerProvider>::EcdsaSigner>, ChannelError>
4618+
where L::Target: Logger
4619+
{
4620+
if !matches!(self.context.channel_state, ChannelState::FundingNegotiated) {
4621+
return Err(ChannelError::Close(
4622+
(
4623+
"Received initial commitment_signed before funding transaction constructed!".to_owned(),
4624+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
4625+
)));
4626+
}
4627+
if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
4628+
self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
4629+
self.context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
4630+
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
4631+
}
4632+
4633+
let funding_script = self.context.get_funding_redeemscript();
4634+
4635+
let counterparty_keys = self.context.build_remote_transaction_keys();
4636+
let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
4637+
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
4638+
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
4639+
4640+
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
4641+
&self.context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
4642+
4643+
let holder_signer = self.context.build_holder_transaction_keys();
4644+
let initial_commitment_tx = self.context.build_commitment_transaction(
4645+
self.context.holder_commitment_point.transaction_number(), &holder_signer, true, false, logger
4646+
).tx;
4647+
{
4648+
let trusted_tx = initial_commitment_tx.trust();
4649+
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
4650+
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
4651+
// They sign our commitment transaction, allowing us to broadcast the tx if we wish.
4652+
if self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.get_counterparty_pubkeys().funding_pubkey).is_err() {
4653+
return Err(ChannelError::Close(
4654+
(
4655+
"Invalid funding_signed signature from peer".to_owned(),
4656+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
4657+
)));
4658+
}
4659+
}
4660+
4661+
let holder_commitment_tx = HolderCommitmentTransaction::new(
4662+
initial_commitment_tx,
4663+
msg.signature,
4664+
Vec::new(),
4665+
&self.context.get_holder_pubkeys().funding_pubkey,
4666+
self.context.counterparty_funding_pubkey()
4667+
);
4668+
4669+
self.context.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, Vec::new())
4670+
.map_err(|_| ChannelError::Close(
4671+
(
4672+
"Failed to validate our commitment".to_owned(),
4673+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
4674+
)))?;
4675+
4676+
let funding_redeemscript = self.context.get_funding_redeemscript();
4677+
let funding_txo = self.context.get_funding_txo().unwrap();
4678+
let funding_txo_script = funding_redeemscript.to_p2wsh();
4679+
let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound());
4680+
let shutdown_script = self.context.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
4681+
let mut monitor_signer = signer_provider.derive_channel_signer(self.context.channel_value_satoshis, self.context.channel_keys_id);
4682+
monitor_signer.provide_channel_parameters(&self.context.channel_transaction_parameters);
4683+
let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer,
4684+
shutdown_script, self.context.get_holder_selected_contest_delay(),
4685+
&self.context.destination_script, (funding_txo, funding_txo_script),
4686+
&self.context.channel_transaction_parameters,
4687+
funding_redeemscript.clone(), self.context.channel_value_satoshis,
4688+
obscure_factor,
4689+
holder_commitment_tx, best_block, self.context.counterparty_node_id, self.context.channel_id());
4690+
4691+
channel_monitor.provide_initial_counterparty_commitment_tx(
4692+
counterparty_initial_bitcoin_tx.txid, Vec::new(),
4693+
self.context.cur_counterparty_commitment_transaction_number,
4694+
self.context.counterparty_cur_commitment_point.unwrap(),
4695+
counterparty_initial_commitment_tx.feerate_per_kw(),
4696+
counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
4697+
counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
4698+
4699+
assert!(!self.context.channel_state.is_monitor_update_in_progress()); // We have no had any monitor(s) yet to fail update!
4700+
self.context.holder_commitment_point.advance(&self.context.holder_signer, &self.context.secp_ctx, logger);
4701+
self.context.cur_counterparty_commitment_transaction_number -= 1;
4702+
4703+
log_info!(logger, "Received initial commitment_signed from peer for channel {}", &self.context.channel_id());
4704+
4705+
let need_channel_ready = self.check_get_channel_ready(0, logger).is_some();
4706+
self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
4707+
4708+
Ok(channel_monitor)
4709+
}
4710+
46164711
pub fn commitment_signed<L: Deref>(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
46174712
where L::Target: Logger
46184713
{
@@ -7848,7 +7943,8 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
78487943
&mut self, msg: &msgs::AcceptChannel, default_limits: &ChannelHandshakeLimits,
78497944
their_features: &InitFeatures
78507945
) -> Result<(), ChannelError> {
7851-
self.context.do_accept_channel_checks(default_limits, their_features, &msg.common_fields, msg.channel_reserve_satoshis)
7946+
self.context.do_accept_channel_checks(
7947+
default_limits, their_features, &msg.common_fields, msg.channel_reserve_satoshis)
78527948
}
78537949

78547950
/// Handles a funding_signed message from the remote end.
@@ -8300,7 +8396,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
83008396
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
83018397
dual_funding_context: DualFundingChannelContext {
83028398
our_funding_satoshis: funding_satoshis,
8303-
their_funding_satoshis: 0,
8399+
their_funding_satoshis: None,
83048400
funding_tx_locktime,
83058401
funding_feerate_sat_per_1000_weight,
83068402
our_funding_inputs: funding_inputs,
@@ -8370,6 +8466,27 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
83708466
require_confirmed_inputs: None,
83718467
}
83728468
}
8469+
8470+
pub fn funding_tx_constructed<L: Deref>(
8471+
mut self, transaction: ConstructedTransaction, logger: &L
8472+
) -> Result<(Channel<SP>, msgs::CommitmentSigned), (Self, ChannelError)>
8473+
where
8474+
L::Target: Logger
8475+
{
8476+
let res = get_initial_commitment_signed(&mut self.context, transaction, logger);
8477+
let commitment_signed = match res {
8478+
Ok(commitment_signed) => commitment_signed,
8479+
Err(err) => return Err((self, err)),
8480+
};
8481+
8482+
let channel = Channel {
8483+
context: self.context,
8484+
dual_funding_channel_context: Some(self.dual_funding_context),
8485+
interactive_tx_constructor: self.interactive_tx_constructor,
8486+
};
8487+
8488+
Ok((channel, commitment_signed))
8489+
}
83738490
}
83748491

83758492
// A not-yet-funded inbound (from counterparty) channel using V2 channel establishment.
@@ -8456,7 +8573,7 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
84568573
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
84578574
dual_funding_context: DualFundingChannelContext {
84588575
our_funding_satoshis: funding_satoshis,
8459-
their_funding_satoshis: msg.common_fields.funding_satoshis,
8576+
their_funding_satoshis: Some(msg.common_fields.funding_satoshis),
84608577
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
84618578
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
84628579
our_funding_inputs: funding_inputs,
@@ -8535,6 +8652,27 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
85358652
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
85368653
self.generate_accept_channel_v2_message()
85378654
}
8655+
8656+
pub fn funding_tx_constructed<L: Deref>(
8657+
mut self, transaction: ConstructedTransaction, logger: &L
8658+
) -> Result<(Channel<SP>, msgs::CommitmentSigned), (Self, ChannelError)>
8659+
where
8660+
L::Target: Logger
8661+
{
8662+
let res = get_initial_commitment_signed(&mut self.context, transaction, logger);
8663+
let commitment_signed = match res {
8664+
Ok(commitment_signed) => commitment_signed,
8665+
Err(err) => return Err((self, err)),
8666+
};
8667+
8668+
let channel = Channel {
8669+
context: self.context,
8670+
dual_funding_channel_context: Some(self.dual_funding_context),
8671+
interactive_tx_constructor: self.interactive_tx_constructor,
8672+
};
8673+
8674+
Ok((channel, commitment_signed))
8675+
}
85388676
}
85398677

85408678
// Unfunded channel utilities
@@ -8562,6 +8700,84 @@ fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures)
85628700
ret
85638701
}
85648702

8703+
fn get_initial_counterparty_commitment_signature<SP:Deref, L: Deref>(
8704+
context: &mut ChannelContext<SP>, logger: &L
8705+
) -> Result<Signature, ChannelError>
8706+
where
8707+
SP::Target: SignerProvider,
8708+
L::Target: Logger
8709+
{
8710+
let counterparty_keys = context.build_remote_transaction_keys();
8711+
let counterparty_initial_commitment_tx = context.build_commitment_transaction(
8712+
context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
8713+
match context.holder_signer {
8714+
// TODO (taproot|arik): move match into calling method for Taproot
8715+
ChannelSignerType::Ecdsa(ref ecdsa) => {
8716+
Ok(ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &context.secp_ctx)
8717+
.map_err(|_| ChannelError::Close(
8718+
(
8719+
"Failed to get signatures for new commitment_signed".to_owned(),
8720+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8721+
)))?.0)
8722+
},
8723+
// TODO (taproot|arik)
8724+
#[cfg(taproot)]
8725+
_ => todo!(),
8726+
}
8727+
}
8728+
8729+
fn get_initial_commitment_signed<SP:Deref, L: Deref>(
8730+
context: &mut ChannelContext<SP>, transaction: ConstructedTransaction, logger: &L
8731+
) -> Result<msgs::CommitmentSigned, ChannelError>
8732+
where
8733+
SP::Target: SignerProvider,
8734+
L::Target: Logger
8735+
{
8736+
if !matches!(
8737+
context.channel_state, ChannelState::NegotiatingFunding(flags)
8738+
if flags == (NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT)) {
8739+
panic!("Tried to get a funding_created messsage at a time other than immediately after initial handshake completion (or tried to get funding_created twice)");
8740+
}
8741+
if context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
8742+
context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
8743+
context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
8744+
panic!("Should not have advanced channel commitment tx numbers prior to initial commitment_signed");
8745+
}
8746+
8747+
let funding_redeemscript = context.get_funding_redeemscript().to_p2wsh();
8748+
let funding_outpoint_index = transaction.outputs().enumerate().find_map(
8749+
|(idx, output)| {
8750+
if output.tx_out().script_pubkey == funding_redeemscript { Some(idx as u16) } else { None }
8751+
}).expect("funding transaction contains funding output");
8752+
let funding_txo = OutPoint { txid: transaction.txid(), index: funding_outpoint_index };
8753+
context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
8754+
context.holder_signer.as_mut().provide_channel_parameters(&context.channel_transaction_parameters);
8755+
8756+
let signature = match get_initial_counterparty_commitment_signature(context, logger) {
8757+
Ok(res) => res,
8758+
Err(e) => {
8759+
log_error!(logger, "Got bad signatures: {:?}!", e);
8760+
context.channel_transaction_parameters.funding_outpoint = None;
8761+
return Err(e);
8762+
}
8763+
};
8764+
8765+
if context.signer_pending_funding {
8766+
log_trace!(logger, "Counterparty commitment signature ready for funding_created message: clearing signer_pending_funding");
8767+
context.signer_pending_funding = false;
8768+
}
8769+
8770+
log_info!(logger, "Generated commitment_signed for peer for channel {}", &context.channel_id());
8771+
8772+
Ok(msgs::CommitmentSigned {
8773+
channel_id: context.channel_id,
8774+
htlc_signatures: vec![],
8775+
signature,
8776+
#[cfg(taproot)]
8777+
partial_signature_with_nonce: None,
8778+
})
8779+
}
8780+
85658781
const SERIALIZATION_VERSION: u8 = 4;
85668782
const MIN_SERIALIZATION_VERSION: u8 = 3;
85678783

0 commit comments

Comments
 (0)