Skip to content

Commit dac491f

Browse files
committed
Handle initial commitment_signed for V2 channels
1 parent 9fafba9 commit dac491f

File tree

3 files changed

+589
-47
lines changed

3 files changed

+589
-47
lines changed

lightning/src/ln/channel.rs

Lines changed: 279 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use bitcoin::locktime::absolute::LockTime;
3131
use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash};
3232
use crate::ln::features::{ChannelTypeFeatures, InitFeatures};
3333
#[cfg(any(dual_funding, splicing))]
34-
use crate::ln::interactivetxs::{estimate_input_weight, get_output_weight, HandleTxCompleteResult, InteractiveTxConstructor, InteractiveTxMessageSend, InteractiveTxMessageSendResult, TX_COMMON_FIELDS_WEIGHT};
34+
use crate::ln::interactivetxs::{ConstructedTransaction, estimate_input_weight, get_output_weight, HandleTxCompleteResult, InteractiveTxConstructor, InteractiveTxMessageSend, InteractiveTxMessageSendResult, TX_COMMON_FIELDS_WEIGHT};
3535
use crate::ln::msgs;
3636
use crate::ln::msgs::DecodeError;
3737
use crate::ln::script::{self, ShutdownScript};
@@ -3825,7 +3825,7 @@ pub(super) struct DualFundingChannelContext {
38253825
/// The amount in satoshis we will be contributing to the channel.
38263826
pub our_funding_satoshis: u64,
38273827
/// The amount in satoshis our counterparty will be contributing to the channel.
3828-
pub their_funding_satoshis: u64,
3828+
pub their_funding_satoshis: Option<u64>,
38293829
/// The funding transaction locktime suggested by the initiator. If set by us, it is always set
38303830
/// to the current block height to align incentives against fee-sniping.
38313831
pub funding_tx_locktime: LockTime,
@@ -4618,6 +4618,106 @@ impl<SP: Deref> Channel<SP> where
46184618
Ok(())
46194619
}
46204620

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

78597960
/// Handles a funding_signed message from the remote end.
@@ -8311,7 +8412,7 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
83118412
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
83128413
dual_funding_context: DualFundingChannelContext {
83138414
our_funding_satoshis: funding_satoshis,
8314-
their_funding_satoshis: 0,
8415+
their_funding_satoshis: None,
83158416
funding_tx_locktime,
83168417
funding_feerate_sat_per_1000_weight,
83178418
our_funding_inputs: funding_inputs,
@@ -8382,6 +8483,46 @@ impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
83828483
require_confirmed_inputs: None,
83838484
}
83848485
}
8486+
8487+
pub fn funding_tx_constructed<L: Deref>(
8488+
mut self, transaction: ConstructedTransaction, est_block: BestBlock, signer_provider: &SP, logger: &L
8489+
) -> Result<(Channel<SP>, msgs::CommitmentSigned), (Self, ChannelError)>
8490+
where
8491+
L::Target: Logger
8492+
{
8493+
let res = get_initial_commitment_signed(&mut self.context, transaction, est_block,
8494+
signer_provider, logger);
8495+
let commitment_signed = match res {
8496+
Ok(commitment_signed) => commitment_signed,
8497+
Err(err) => return Err((self, err)),
8498+
};
8499+
8500+
let channel = Channel {
8501+
context: self.context,
8502+
dual_funding_channel_context: Some(self.dual_funding_context),
8503+
interactive_tx_constructor: self.interactive_tx_constructor,
8504+
};
8505+
8506+
Ok((channel, commitment_signed))
8507+
}
8508+
8509+
pub fn accept_channel_v2(
8510+
&mut self, msg: &msgs::AcceptChannelV2, default_limits: &ChannelHandshakeLimits,
8511+
their_features: &InitFeatures,
8512+
) -> Result<(), ChannelError> {
8513+
// According to the spec we MUST fail the negotiation if `require_confirmed_inputs` is set in
8514+
// `accept_channel2` but we cannot provide confirmed inputs. We're not going to check if the user
8515+
// upheld this requirement, so we just defer the failure to the counterparty's checks during
8516+
// interactive transaction construction and remain blissfully unaware here.
8517+
8518+
// Now we can generate the `channel_id` since we have our counterparty's `revocation_basepoint`.
8519+
self.context.channel_id = ChannelId::v2_from_revocation_basepoints(
8520+
&self.context.get_holder_pubkeys().revocation_basepoint, &RevocationBasepoint::from(msg.common_fields.revocation_basepoint));
8521+
self.dual_funding_context.their_funding_satoshis = Some(msg.funding_satoshis);
8522+
self.context.do_accept_channel_checks(
8523+
default_limits, their_features, &msg.common_fields, get_v2_channel_reserve_satoshis(
8524+
msg.common_fields.dust_limit_satoshis, self.context.channel_value_satoshis))
8525+
}
83858526
}
83868527

83878528
// A not-yet-funded inbound (from counterparty) channel using V2 channel establishment.
@@ -8470,7 +8611,7 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
84708611
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
84718612
dual_funding_context: DualFundingChannelContext {
84728613
our_funding_satoshis: funding_satoshis,
8473-
their_funding_satoshis: msg.common_fields.funding_satoshis,
8614+
their_funding_satoshis: Some(msg.common_fields.funding_satoshis),
84748615
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
84758616
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
84768617
our_funding_inputs: funding_inputs,
@@ -8549,6 +8690,28 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
85498690
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
85508691
self.generate_accept_channel_v2_message()
85518692
}
8693+
8694+
pub fn funding_tx_constructed<L: Deref>(
8695+
mut self, transaction: ConstructedTransaction, est_block: BestBlock, signer_provider: &SP, logger: &L
8696+
) -> Result<(Channel<SP>, msgs::CommitmentSigned), (Self, ChannelError)>
8697+
where
8698+
L::Target: Logger
8699+
{
8700+
let res = get_initial_commitment_signed(&mut self.context, transaction, est_block,
8701+
signer_provider, logger);
8702+
let commitment_signed = match res {
8703+
Ok(commitment_signed) => commitment_signed,
8704+
Err(err) => return Err((self, err)),
8705+
};
8706+
8707+
let channel = Channel {
8708+
context: self.context,
8709+
dual_funding_channel_context: Some(self.dual_funding_context),
8710+
interactive_tx_constructor: self.interactive_tx_constructor,
8711+
};
8712+
8713+
Ok((channel, commitment_signed))
8714+
}
85528715
}
85538716

85548717
// Unfunded channel utilities
@@ -8576,6 +8739,117 @@ fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures)
85768739
ret
85778740
}
85788741

8742+
/// If an Err is returned, it is a ChannelError::Close
8743+
#[cfg(any(dual_funding, splicing))]
8744+
fn get_initial_remote_commitment_tx_signature<SP:Deref, L: Deref>(
8745+
context: &mut ChannelContext<SP>, logger: &L
8746+
) -> Result<(CommitmentTransaction, Signature), ChannelError>
8747+
where
8748+
SP::Target: SignerProvider,
8749+
L::Target: Logger
8750+
{
8751+
let counterparty_keys = context.build_remote_transaction_keys();
8752+
let counterparty_initial_commitment_tx = context.build_commitment_transaction(
8753+
context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
8754+
8755+
let holder_keys = context.build_holder_transaction_keys();
8756+
let initial_commitment_tx = context.build_commitment_transaction(
8757+
context.holder_commitment_point.transaction_number(), &holder_keys, true, true, logger).tx;
8758+
8759+
match &context.holder_signer {
8760+
ChannelSignerType::Ecdsa(ecdsa) => {
8761+
let signature = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &context.secp_ctx)
8762+
.map_err(|_| ChannelError::Close(
8763+
(
8764+
"Failed to get signatures for new commitment_signed".to_owned(),
8765+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8766+
)
8767+
))?.0;
8768+
Ok((counterparty_initial_commitment_tx, signature))
8769+
}
8770+
}
8771+
}
8772+
8773+
#[cfg(any(dual_funding, splicing))]
8774+
fn get_initial_counterparty_commitment_signature<SP:Deref, L: Deref>(
8775+
context: &mut ChannelContext<SP>, logger: &L
8776+
) -> Result<Signature, ChannelError>
8777+
where
8778+
SP::Target: SignerProvider,
8779+
L::Target: Logger
8780+
{
8781+
let counterparty_keys = context.build_remote_transaction_keys();
8782+
let counterparty_initial_commitment_tx = context.build_commitment_transaction(
8783+
context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
8784+
match context.holder_signer {
8785+
// TODO (taproot|arik): move match into calling method for Taproot
8786+
ChannelSignerType::Ecdsa(ref ecdsa) => {
8787+
Ok(ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &context.secp_ctx)
8788+
.map_err(|_| ChannelError::Close(
8789+
(
8790+
"Failed to get signatures for new commitment_signed".to_owned(),
8791+
ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) },
8792+
)))?.0)
8793+
},
8794+
// TODO (taproot|arik)
8795+
#[cfg(taproot)]
8796+
_ => todo!(),
8797+
}
8798+
}
8799+
8800+
#[cfg(any(dual_funding, splicing))]
8801+
fn get_initial_commitment_signed<SP:Deref, L: Deref>(
8802+
context: &mut ChannelContext<SP>, transaction: ConstructedTransaction, est_block: BestBlock, signer_provider: &SP, logger: &L
8803+
) -> Result<msgs::CommitmentSigned, ChannelError>
8804+
where
8805+
SP::Target: SignerProvider,
8806+
L::Target: Logger
8807+
{
8808+
if !matches!(
8809+
context.channel_state, ChannelState::NegotiatingFunding(flags)
8810+
if flags == (NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT)) {
8811+
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)");
8812+
}
8813+
if context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
8814+
context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
8815+
context.holder_commitment_point.transaction_number() != INITIAL_COMMITMENT_NUMBER {
8816+
panic!("Should not have advanced channel commitment tx numbers prior to initial commitment_signed");
8817+
}
8818+
8819+
let funding_redeemscript = context.get_funding_redeemscript().to_p2wsh();
8820+
let funding_outpoint_index = transaction.outputs().enumerate().find_map(
8821+
|(idx, output)| {
8822+
if output.tx_out().script_pubkey == funding_redeemscript { Some(idx as u16) } else { None }
8823+
}).expect("funding transaction contains funding output");
8824+
let funding_txo = OutPoint { txid: transaction.txid(), index: funding_outpoint_index };
8825+
context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
8826+
context.holder_signer.as_mut().provide_channel_parameters(&context.channel_transaction_parameters);
8827+
8828+
let signature = match get_initial_counterparty_commitment_signature(context, logger) {
8829+
Ok(res) => res,
8830+
Err(e) => {
8831+
log_error!(logger, "Got bad signatures: {:?}!", e);
8832+
context.channel_transaction_parameters.funding_outpoint = None;
8833+
return Err(e);
8834+
}
8835+
};
8836+
8837+
if context.signer_pending_funding {
8838+
log_trace!(logger, "Counterparty commitment signature ready for funding_created message: clearing signer_pending_funding");
8839+
context.signer_pending_funding = false;
8840+
}
8841+
8842+
log_info!(logger, "Generated commitment_signed for peer for channel {}", &context.channel_id());
8843+
8844+
Ok(msgs::CommitmentSigned {
8845+
channel_id: context.channel_id.clone(),
8846+
htlc_signatures: vec![],
8847+
signature,
8848+
#[cfg(taproot)]
8849+
partial_signature_with_nonce: None,
8850+
})
8851+
}
8852+
85798853
const SERIALIZATION_VERSION: u8 = 4;
85808854
const MIN_SERIALIZATION_VERSION: u8 = 3;
85818855

0 commit comments

Comments
 (0)