Skip to content

Commit d83bb15

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 2bdff0d commit d83bb15

File tree

1 file changed

+67
-55
lines changed

1 file changed

+67
-55
lines changed

lightning/src/ln/channel.rs

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,43 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
21292129
next_local_nonce: None,
21302130
})
21312131
}
2132+
2133+
/// Only allowed after [`Self::channel_transaction_parameters`] is set.
2134+
fn get_funding_signed_msg<L: Deref>(&mut self, logger: &L) -> (CommitmentTransaction, Option<msgs::FundingSigned>) where L::Target: Logger {
2135+
let counterparty_keys = self.build_remote_transaction_keys();
2136+
let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number + 1, &counterparty_keys, false, false, logger).tx;
2137+
2138+
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
2139+
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
2140+
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
2141+
&self.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
2142+
2143+
match &self.holder_signer {
2144+
// TODO (arik): move match into calling method for Taproot
2145+
ChannelSignerType::Ecdsa(ecdsa) => {
2146+
let funding_signed = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
2147+
.map(|(signature, _)| msgs::FundingSigned {
2148+
channel_id: self.channel_id(),
2149+
signature,
2150+
#[cfg(taproot)]
2151+
partial_signature_with_nonce: None,
2152+
})
2153+
.ok();
2154+
2155+
if funding_signed.is_none() {
2156+
log_trace!(logger, "Counterparty commitment signature not available for funding_signed message; setting signer_pending_funding");
2157+
self.signer_pending_funding = true;
2158+
} else if self.signer_pending_funding {
2159+
log_trace!(logger, "Counterparty commitment signature available for funding_signed message; clearing signer_pending_funding");
2160+
self.signer_pending_funding = false;
2161+
}
2162+
2163+
// We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
2164+
(counterparty_initial_commitment_tx, funding_signed)
2165+
}
2166+
}
2167+
}
2168+
21322169
}
21332170

21342171
// Internal utility functions for channels
@@ -3957,8 +3994,12 @@ impl<SP: Deref> Channel<SP> where
39573994
let commitment_update = if self.context.signer_pending_commitment_update {
39583995
self.get_last_commitment_update_for_send(logger).ok()
39593996
} else { None };
3960-
let funding_signed = None;
3961-
let channel_ready = None;
3997+
let funding_signed = if self.context.signer_pending_funding && !self.context.is_outbound() {
3998+
self.context.get_funding_signed_msg(logger).1
3999+
} else { None };
4000+
let channel_ready = if funding_signed.is_some() {
4001+
self.check_get_channel_ready(0)
4002+
} else { None };
39624003
let funding_created = if self.context.signer_pending_funding && self.context.is_outbound() {
39634004
self.context.get_funding_created_msg(logger)
39644005
} else { None };
@@ -6730,41 +6771,22 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67306771
self.generate_accept_channel_message()
67316772
}
67326773

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

67366777
let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
67376778
let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
6738-
{
6739-
let trusted_tx = initial_commitment_tx.trust();
6740-
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
6741-
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
6742-
// They sign the holder commitment transaction...
6743-
log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
6744-
log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
6745-
encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
6746-
encode::serialize_hex(&funding_script), &self.context.channel_id());
6747-
secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
6748-
}
6749-
6750-
let counterparty_keys = self.context.build_remote_transaction_keys();
6751-
let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
6752-
6753-
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
6754-
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
6755-
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
6756-
&self.context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
6757-
6758-
match &self.context.holder_signer {
6759-
// TODO (arik): move match into calling method for Taproot
6760-
ChannelSignerType::Ecdsa(ecdsa) => {
6761-
let counterparty_signature = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
6762-
.map(|(sig, _)| sig).ok();
6779+
let trusted_tx = initial_commitment_tx.trust();
6780+
let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
6781+
let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
6782+
// They sign the holder commitment transaction...
6783+
log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
6784+
log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
6785+
encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
6786+
encode::serialize_hex(&funding_script), &self.context.channel_id());
6787+
secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
67636788

6764-
// We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
6765-
Ok((counterparty_initial_commitment_tx, initial_commitment_tx, counterparty_signature))
6766-
}
6767-
}
6789+
Ok(initial_commitment_tx)
67686790
}
67696791

67706792
pub fn funding_created<L: Deref>(
@@ -6791,10 +6813,10 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
67916813
let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index };
67926814
self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
67936815
// This is an externally observable change before we finish all our checks. In particular
6794-
// funding_created_signature may fail.
6816+
// check_funding_created_signature may fail.
67956817
self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters);
67966818

6797-
let (counterparty_initial_commitment_tx, initial_commitment_tx, sig_opt) = match self.funding_created_signature(&msg.signature, logger) {
6819+
let initial_commitment_tx = match self.check_funding_created_signature(&msg.signature, logger) {
67986820
Ok(res) => res,
67996821
Err(ChannelError::Close(e)) => {
68006822
self.context.channel_transaction_parameters.funding_outpoint = None;
@@ -6803,7 +6825,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
68036825
Err(e) => {
68046826
// The only error we know how to handle is ChannelError::Close, so we fall over here
68056827
// to make sure we don't continue with an inconsistent state.
6806-
panic!("unexpected error type from funding_created_signature {:?}", e);
6828+
panic!("unexpected error type from check_funding_created_signature {:?}", e);
68076829
}
68086830
};
68096831

@@ -6821,6 +6843,13 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
68216843

68226844
// Now that we're past error-generating stuff, update our local state:
68236845

6846+
self.context.channel_state = ChannelState::FundingSent as u32;
6847+
self.context.channel_id = funding_txo.to_channel_id();
6848+
self.context.cur_counterparty_commitment_transaction_number -= 1;
6849+
self.context.cur_holder_commitment_transaction_number -= 1;
6850+
6851+
let (counterparty_initial_commitment_tx, funding_signed) = self.context.get_funding_signed_msg(logger);
6852+
68246853
let funding_redeemscript = self.context.get_funding_redeemscript();
68256854
let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
68266855
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());
@@ -6837,39 +6866,22 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
68376866

68386867
channel_monitor.provide_initial_counterparty_commitment_tx(
68396868
counterparty_initial_commitment_tx.trust().txid(), Vec::new(),
6840-
self.context.cur_counterparty_commitment_transaction_number,
6869+
self.context.cur_counterparty_commitment_transaction_number + 1,
68416870
self.context.counterparty_cur_commitment_point.unwrap(), self.context.feerate_per_kw,
68426871
counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
68436872
counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
68446873

6845-
self.context.channel_state = ChannelState::FundingSent as u32;
6846-
self.context.channel_id = funding_txo.to_channel_id();
6847-
self.context.cur_counterparty_commitment_transaction_number -= 1;
6848-
self.context.cur_holder_commitment_transaction_number -= 1;
6849-
6850-
log_info!(logger, "Generated funding_signed for peer for channel {}", &self.context.channel_id());
6874+
log_info!(logger, "{} funding_signed for peer for channel {}",
6875+
if funding_signed.is_some() { "Generated" } else { "Waiting for signature on" }, &self.context.channel_id());
68516876

68526877
// Promote the channel to a full-fledged one now that we have updated the state and have a
68536878
// `ChannelMonitor`.
68546879
let mut channel = Channel {
68556880
context: self.context,
68566881
};
6857-
let channel_id = channel.context.channel_id.clone();
68586882
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
68596883
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
68606884

6861-
let funding_signed = if let Some(signature) = sig_opt {
6862-
Some(msgs::FundingSigned {
6863-
channel_id,
6864-
signature,
6865-
#[cfg(taproot)]
6866-
partial_signature_with_nonce: None,
6867-
})
6868-
} else {
6869-
channel.context.signer_pending_funding = true;
6870-
None
6871-
};
6872-
68736885
Ok((channel, funding_signed, channel_monitor))
68746886
}
68756887
}

0 commit comments

Comments
 (0)