Skip to content

Commit d5db1fb

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 2d93444 commit d5db1fb

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
@@ -2121,6 +2121,36 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
21212121
next_local_nonce: None,
21222122
})
21232123
}
2124+
2125+
/// Only allowed after [`Self::channel_transaction_parameters`] is set.
2126+
fn get_funding_signed_msg<L: Deref>(&mut self, logger: &L) -> (CommitmentTransaction, Option<msgs::FundingSigned>) where L::Target: Logger {
2127+
let counterparty_keys = self.build_remote_transaction_keys();
2128+
let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number + 1, &counterparty_keys, false, false, logger).tx;
2129+
2130+
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
2131+
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
2132+
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
2133+
&self.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
2134+
2135+
match &self.holder_signer {
2136+
// TODO (arik): move match into calling method for Taproot
2137+
ChannelSignerType::Ecdsa(ecdsa) => {
2138+
let funding_signed = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
2139+
.map(|(signature, _)| msgs::FundingSigned {
2140+
channel_id: self.channel_id(),
2141+
signature,
2142+
#[cfg(taproot)]
2143+
partial_signature_with_nonce: None,
2144+
})
2145+
.ok();
2146+
self.signer_pending_funding = funding_signed.is_none();
2147+
2148+
// We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
2149+
(counterparty_initial_commitment_tx, funding_signed)
2150+
}
2151+
}
2152+
}
2153+
21242154
}
21252155

21262156
// Internal utility functions for channels
@@ -3949,7 +3979,9 @@ impl<SP: Deref> Channel<SP> where
39493979
let commitment_update = if self.context.signer_pending_commitment_update {
39503980
self.get_last_commitment_update_for_send(logger).ok()
39513981
} else { None };
3952-
let funding_signed = None;
3982+
let funding_signed = if self.context.signer_pending_funding && !self.context.is_outbound() {
3983+
self.context.get_funding_signed_msg(logger).1
3984+
} else { None };
39533985
let funding_created = if self.context.signer_pending_funding && self.context.is_outbound() {
39543986
self.context.get_funding_created_msg(logger)
39553987
} else { None };
@@ -6682,41 +6714,22 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
66826714
self.generate_accept_channel_message()
66836715
}
66846716

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

66886720
let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
66896721
let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
6690-
{
6691-
let trusted_tx = initial_commitment_tx.trust();
6692-
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
6693-
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
6694-
// They sign the holder commitment transaction...
6695-
log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
6696-
log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
6697-
encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
6698-
encode::serialize_hex(&funding_script), &self.context.channel_id());
6699-
secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
6700-
}
6701-
6702-
let counterparty_keys = self.context.build_remote_transaction_keys();
6703-
let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
6704-
6705-
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
6706-
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
6707-
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
6708-
&self.context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
6709-
6710-
match &self.context.holder_signer {
6711-
// TODO (arik): move match into calling method for Taproot
6712-
ChannelSignerType::Ecdsa(ecdsa) => {
6713-
let counterparty_signature = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
6714-
.map(|(sig, _)| sig).ok();
6722+
let trusted_tx = initial_commitment_tx.trust();
6723+
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
6724+
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
6725+
// They sign the holder commitment transaction...
6726+
log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
6727+
log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
6728+
encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
6729+
encode::serialize_hex(&funding_script), &self.context.channel_id());
6730+
secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
67156731

6716-
// We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
6717-
Ok((counterparty_initial_commitment_tx, initial_commitment_tx, counterparty_signature))
6718-
}
6719-
}
6732+
Ok(initial_commitment_tx)
67206733
}
67216734

67226735
pub fn funding_created<L: Deref>(
@@ -6743,10 +6756,10 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67436756
let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index };
67446757
self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
67456758
// This is an externally observable change before we finish all our checks. In particular
6746-
// funding_created_signature may fail.
6759+
// check_funding_created_signature may fail.
67476760
self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters);
67486761

6749-
let (counterparty_initial_commitment_tx, initial_commitment_tx, sig_opt) = match self.funding_created_signature(&msg.signature, logger) {
6762+
let initial_commitment_tx = match self.check_funding_created_signature(&msg.signature, logger) {
67506763
Ok(res) => res,
67516764
Err(ChannelError::Close(e)) => {
67526765
self.context.channel_transaction_parameters.funding_outpoint = None;
@@ -6755,7 +6768,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67556768
Err(e) => {
67566769
// The only error we know how to handle is ChannelError::Close, so we fall over here
67576770
// to make sure we don't continue with an inconsistent state.
6758-
panic!("unexpected error type from funding_created_signature {:?}", e);
6771+
panic!("unexpected error type from check_funding_created_signature {:?}", e);
67596772
}
67606773
};
67616774

@@ -6771,6 +6784,13 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67716784
return Err((self, ChannelError::Close("Failed to validate our commitment".to_owned())));
67726785
}
67736786

6787+
self.context.channel_state = ChannelState::FundingSent as u32;
6788+
self.context.channel_id = funding_txo.to_channel_id();
6789+
self.context.cur_counterparty_commitment_transaction_number -= 1;
6790+
self.context.cur_holder_commitment_transaction_number -= 1;
6791+
6792+
let (counterparty_initial_commitment_tx, funding_signed) = self.context.get_funding_signed_msg(logger);
6793+
67746794
// Now that we're past error-generating stuff, update our local state:
67756795

67766796
let funding_redeemscript = self.context.get_funding_redeemscript();
@@ -6789,16 +6809,11 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67896809

67906810
channel_monitor.provide_initial_counterparty_commitment_tx(
67916811
counterparty_initial_commitment_tx.trust().txid(), Vec::new(),
6792-
self.context.cur_counterparty_commitment_transaction_number,
6812+
self.context.cur_counterparty_commitment_transaction_number + 1,
67936813
self.context.counterparty_cur_commitment_point.unwrap(), self.context.feerate_per_kw,
67946814
counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
67956815
counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
67966816

6797-
self.context.channel_state = ChannelState::FundingSent as u32;
6798-
self.context.channel_id = funding_txo.to_channel_id();
6799-
self.context.cur_counterparty_commitment_transaction_number -= 1;
6800-
self.context.cur_holder_commitment_transaction_number -= 1;
6801-
68026817
log_info!(logger, "Generated funding_signed for peer for channel {}", &self.context.channel_id());
68036818

68046819
// Promote the channel to a full-fledged one now that we have updated the state and have a
@@ -6810,18 +6825,6 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
68106825
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
68116826
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
68126827

6813-
let funding_signed = if let Some(signature) = sig_opt {
6814-
Some(msgs::FundingSigned {
6815-
channel_id,
6816-
signature,
6817-
#[cfg(taproot)]
6818-
partial_signature_with_nonce: None,
6819-
})
6820-
} else {
6821-
channel.context.signer_pending_funding = true;
6822-
None
6823-
};
6824-
68256828
Ok((channel, funding_signed, channel_monitor))
68266829
}
68276830
}

0 commit comments

Comments
 (0)