Skip to content

Commit 2bdff0d

Browse files
TheBlueMattwaterson
authored andcommitted
Handle retrying sign_counterparty_commitment outb 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 outbound funding_created signing failures, regenerating the `FundingCreated` message, attempting to re-sign, and sending it to our peers if we succeed.
1 parent 8dfc1e5 commit 2bdff0d

File tree

1 file changed

+39
-30
lines changed

1 file changed

+39
-30
lines changed

lightning/src/ln/channel.rs

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,6 +2100,35 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
21002100
unbroadcasted_batch_funding_txid,
21012101
}
21022102
}
2103+
2104+
/// Only allowed after [`Self::channel_transaction_parameters`] is set.
2105+
fn get_funding_created_msg<L: Deref>(&mut self, logger: &L) -> Option<msgs::FundingCreated> where L::Target: Logger {
2106+
let counterparty_keys = self.build_remote_transaction_keys();
2107+
let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
2108+
let signature = match &self.holder_signer {
2109+
// TODO (taproot|arik): move match into calling method for Taproot
2110+
ChannelSignerType::Ecdsa(ecdsa) => {
2111+
ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
2112+
.map(|(sig, _)| sig).ok()?
2113+
}
2114+
};
2115+
2116+
if self.signer_pending_funding {
2117+
log_trace!(logger, "Counterparty commitment signature ready for funding_created message: clearing signer_pending_funding");
2118+
self.signer_pending_funding = false;
2119+
}
2120+
2121+
Some(msgs::FundingCreated {
2122+
temporary_channel_id: self.temporary_channel_id.unwrap(),
2123+
funding_txid: self.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().txid,
2124+
funding_output_index: self.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().index,
2125+
signature,
2126+
#[cfg(taproot)]
2127+
partial_signature_with_nonce: None,
2128+
#[cfg(taproot)]
2129+
next_local_nonce: None,
2130+
})
2131+
}
21032132
}
21042133

21052134
// Internal utility functions for channels
@@ -3930,7 +3959,9 @@ impl<SP: Deref> Channel<SP> where
39303959
} else { None };
39313960
let funding_signed = None;
39323961
let channel_ready = None;
3933-
let funding_created = None;
3962+
let funding_created = if self.context.signer_pending_funding && self.context.is_outbound() {
3963+
self.context.get_funding_created_msg(logger)
3964+
} else { None };
39343965

39353966
log_trace!(logger, "Signer unblocked with {} commitment_update, {} funding_signed, {} funding_created, and {} channel_ready",
39363967
if commitment_update.is_some() { "a" } else { "no" },
@@ -6000,18 +6031,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
60006031
})
60016032
}
60026033

6003-
fn get_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ()> where L::Target: Logger {
6004-
let counterparty_keys = self.context.build_remote_transaction_keys();
6005-
let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
6006-
match &self.context.holder_signer {
6007-
// TODO (taproot|arik): move match into calling method for Taproot
6008-
ChannelSignerType::Ecdsa(ecdsa) => {
6009-
ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
6010-
.map(|(sig, _)| sig)
6011-
}
6012-
}
6013-
}
6014-
60156034
/// Updates channel state with knowledge of the funding transaction's txid/index, and generates
60166035
/// a funding_created message for the remote peer.
60176036
/// Panics if called at some time other than immediately after initial handshake, if called twice,
@@ -6036,8 +6055,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
60366055
self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
60376056
self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters);
60386057

6039-
let temporary_channel_id = self.context.channel_id;
6040-
60416058
// Now that we're past error-generating stuff, update our local state:
60426059

60436060
self.context.channel_state = ChannelState::FundingCreated as u32;
@@ -6054,21 +6071,13 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
60546071
self.context.funding_transaction = Some(funding_transaction);
60556072
self.context.is_batch_funding = Some(()).filter(|_| is_batch_funding);
60566073

6057-
let funding_created = if let Ok(signature) = self.get_funding_created_signature(logger) {
6058-
Some(msgs::FundingCreated {
6059-
temporary_channel_id,
6060-
funding_txid: funding_txo.txid,
6061-
funding_output_index: funding_txo.index,
6062-
signature,
6063-
#[cfg(taproot)]
6064-
partial_signature_with_nonce: None,
6065-
#[cfg(taproot)]
6066-
next_local_nonce: None,
6067-
})
6068-
} else {
6069-
self.context.signer_pending_funding = true;
6070-
None
6071-
};
6074+
let funding_created = self.context.get_funding_created_msg(logger);
6075+
if funding_created.is_none() {
6076+
if !self.context.signer_pending_funding {
6077+
log_trace!(logger, "funding_created awaiting signer; setting signer_pending_funding");
6078+
self.context.signer_pending_funding = true;
6079+
}
6080+
}
60726081

60736082
let channel = Channel {
60746083
context: self.context,

0 commit comments

Comments
 (0)