Skip to content

Commit 36eb249

Browse files
TheBlueMattwaterson
authored andcommitted
Handle retrying sign_counterparty_commitment inb funding failures
If sign_counterparty_commitment fails (i.e. because the signer is temporarily disconnected), this really indicates that we should retry the message sending which required the signature later, rather than force-closing the channel (which probably won't even work if the signer is missing). This commit adds retrying of inbound funding_created signing failures, regenerating the `FundingSigned` message, attempting to re-sign, and sending it to our peers if we succeed.
1 parent 3a6bd3d commit 36eb249

File tree

1 file changed

+55
-52
lines changed

1 file changed

+55
-52
lines changed

lightning/src/ln/channel.rs

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,6 +2110,36 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
21102110
next_local_nonce: None,
21112111
})
21122112
}
2113+
2114+
/// Only allowed after [`Self::channel_transaction_parameters`] is set.
2115+
fn get_funding_signed_msg<L: Deref>(&mut self, logger: &L) -> (CommitmentTransaction, Option<msgs::FundingSigned>) where L::Target: Logger {
2116+
let counterparty_keys = self.build_remote_transaction_keys();
2117+
let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number + 1, &counterparty_keys, false, false, logger).tx;
2118+
2119+
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
2120+
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
2121+
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
2122+
&self.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
2123+
2124+
match &self.holder_signer {
2125+
// TODO (arik): move match into calling method for Taproot
2126+
ChannelSignerType::Ecdsa(ecdsa) => {
2127+
let funding_signed = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
2128+
.map(|(signature, _)| msgs::FundingSigned {
2129+
channel_id: self.channel_id(),
2130+
signature,
2131+
#[cfg(taproot)]
2132+
partial_signature_with_nonce: None,
2133+
})
2134+
.ok();
2135+
self.signer_pending_funding = funding_signed.is_none();
2136+
2137+
// We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
2138+
(counterparty_initial_commitment_tx, funding_signed)
2139+
}
2140+
}
2141+
}
2142+
21132143
}
21142144

21152145
// Internal utility functions for channels
@@ -3935,7 +3965,9 @@ impl<SP: Deref> Channel<SP> where
39353965
let commitment_update = if self.context.signer_pending_commitment_update {
39363966
self.get_last_commitment_update_for_send(logger).ok()
39373967
} else { None };
3938-
let funding_signed = None;
3968+
let funding_signed = if self.context.signer_pending_funding && !self.context.is_outbound() {
3969+
self.context.get_funding_signed_msg(logger).1
3970+
} else { None };
39393971
let funding_created = if self.context.signer_pending_funding && self.context.is_outbound() {
39403972
self.context.get_funding_created_msg(logger)
39413973
} else { None };
@@ -6661,41 +6693,22 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
66616693
self.generate_accept_channel_message()
66626694
}
66636695

6664-
fn funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<(CommitmentTransaction, CommitmentTransaction, Option<Signature>), ChannelError> where L::Target: Logger {
6696+
fn check_funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<CommitmentTransaction, ChannelError> where L::Target: Logger {
66656697
let funding_script = self.context.get_funding_redeemscript();
66666698

66676699
let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
66686700
let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
6669-
{
6670-
let trusted_tx = initial_commitment_tx.trust();
6671-
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
6672-
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
6673-
// They sign the holder commitment transaction...
6674-
log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
6675-
log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
6676-
encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
6677-
encode::serialize_hex(&funding_script), &self.context.channel_id());
6678-
secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
6679-
}
6680-
6681-
let counterparty_keys = self.context.build_remote_transaction_keys();
6682-
let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
6683-
6684-
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
6685-
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
6686-
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
6687-
&self.context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
6688-
6689-
match &self.context.holder_signer {
6690-
// TODO (arik): move match into calling method for Taproot
6691-
ChannelSignerType::Ecdsa(ecdsa) => {
6692-
let counterparty_signature = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
6693-
.map(|(sig, _)| sig).ok();
6701+
let trusted_tx = initial_commitment_tx.trust();
6702+
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
6703+
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
6704+
// They sign the holder commitment transaction...
6705+
log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
6706+
log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
6707+
encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
6708+
encode::serialize_hex(&funding_script), &self.context.channel_id());
6709+
secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
66946710

6695-
// We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
6696-
Ok((counterparty_initial_commitment_tx, initial_commitment_tx, counterparty_signature))
6697-
}
6698-
}
6711+
Ok(initial_commitment_tx)
66996712
}
67006713

67016714
pub fn funding_created<L: Deref>(
@@ -6722,10 +6735,10 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67226735
let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index };
67236736
self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
67246737
// This is an externally observable change before we finish all our checks. In particular
6725-
// funding_created_signature may fail.
6738+
// check_funding_created_signature may fail.
67266739
self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters);
67276740

6728-
let (counterparty_initial_commitment_tx, initial_commitment_tx, sig_opt) = match self.funding_created_signature(&msg.signature, logger) {
6741+
let initial_commitment_tx = match self.check_funding_created_signature(&msg.signature, logger) {
67296742
Ok(res) => res,
67306743
Err(ChannelError::Close(e)) => {
67316744
self.context.channel_transaction_parameters.funding_outpoint = None;
@@ -6734,7 +6747,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67346747
Err(e) => {
67356748
// The only error we know how to handle is ChannelError::Close, so we fall over here
67366749
// to make sure we don't continue with an inconsistent state.
6737-
panic!("unexpected error type from funding_created_signature {:?}", e);
6750+
panic!("unexpected error type from check_funding_created_signature {:?}", e);
67386751
}
67396752
};
67406753

@@ -6750,6 +6763,13 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67506763
return Err((self, ChannelError::Close("Failed to validate our commitment".to_owned())));
67516764
}
67526765

6766+
self.context.channel_state = ChannelState::FundingSent as u32;
6767+
self.context.channel_id = funding_txo.to_channel_id();
6768+
self.context.cur_counterparty_commitment_transaction_number -= 1;
6769+
self.context.cur_holder_commitment_transaction_number -= 1;
6770+
6771+
let (counterparty_initial_commitment_tx, funding_signed) = self.context.get_funding_signed_msg(logger);
6772+
67536773
// Now that we're past error-generating stuff, update our local state:
67546774

67556775
let funding_redeemscript = self.context.get_funding_redeemscript();
@@ -6768,16 +6788,11 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67686788

67696789
channel_monitor.provide_initial_counterparty_commitment_tx(
67706790
counterparty_initial_commitment_tx.trust().txid(), Vec::new(),
6771-
self.context.cur_counterparty_commitment_transaction_number,
6791+
self.context.cur_counterparty_commitment_transaction_number + 1,
67726792
self.context.counterparty_cur_commitment_point.unwrap(), self.context.feerate_per_kw,
67736793
counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
67746794
counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
67756795

6776-
self.context.channel_state = ChannelState::FundingSent as u32;
6777-
self.context.channel_id = funding_txo.to_channel_id();
6778-
self.context.cur_counterparty_commitment_transaction_number -= 1;
6779-
self.context.cur_holder_commitment_transaction_number -= 1;
6780-
67816796
log_info!(logger, "Generated funding_signed for peer for channel {}", &self.context.channel_id());
67826797

67836798
// Promote the channel to a full-fledged one now that we have updated the state and have a
@@ -6789,18 +6804,6 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67896804
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
67906805
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
67916806

6792-
let funding_signed = if let Some(signature) = sig_opt {
6793-
Some(msgs::FundingSigned {
6794-
channel_id,
6795-
signature,
6796-
#[cfg(taproot)]
6797-
partial_signature_with_nonce: None,
6798-
})
6799-
} else {
6800-
channel.context.signer_pending_funding = true;
6801-
None
6802-
};
6803-
68046807
Ok((channel, funding_signed, channel_monitor))
68056808
}
68066809
}

0 commit comments

Comments
 (0)