Skip to content

Commit 242b20d

Browse files
committed
Allow holder commitment and HTLC signature requests to fail
As part of the ongoing async signer work, our holder signatures must also be capable of being obtained asynchronously. We rely on our existing `ChainMonitor::rebroadcast_pending_claims` method to retry pending onchain claims by re-signing and rebroadcasting transactions. Unfortunately, we cannot retry said claims without them being registered first, so if we're not able to obtain the signature synchronously, we must return the transaction as unsigned and ensure it is not broadcast.
1 parent 15c9f5b commit 242b20d

File tree

7 files changed

+226
-69
lines changed

7 files changed

+226
-69
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,8 +1396,8 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
13961396
/// Loads the funding txo and outputs to watch into the given `chain::Filter` by repeatedly
13971397
/// calling `chain::Filter::register_output` and `chain::Filter::register_tx` until all outputs
13981398
/// have been registered.
1399-
pub fn load_outputs_to_watch<F: Deref, L: Deref>(&self, filter: &F, logger: &L)
1400-
where
1399+
pub fn load_outputs_to_watch<F: Deref, L: Deref>(&self, filter: &F, logger: &L)
1400+
where
14011401
F::Target: chain::Filter, L::Target: Logger,
14021402
{
14031403
let lock = self.inner.lock().unwrap();
@@ -1542,21 +1542,16 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
15421542
self.inner.lock().unwrap().counterparty_node_id
15431543
}
15441544

1545-
/// Used by [`ChannelManager`] deserialization to broadcast the latest holder state if its copy
1546-
/// of the channel state was out-of-date.
1547-
///
1548-
/// You may also use this to broadcast the latest local commitment transaction, either because
1545+
/// You may use this to broadcast the latest local commitment transaction, either because
15491546
/// a monitor update failed or because we've fallen behind (i.e. we've received proof that our
15501547
/// counterparty side knows a revocation secret we gave them that they shouldn't know).
15511548
///
1552-
/// Broadcasting these transactions in the second case is UNSAFE, as they allow counterparty
1549+
/// Broadcasting these transactions in this manner is UNSAFE, as they allow counterparty
15531550
/// side to punish you. Nevertheless you may want to broadcast them if counterparty doesn't
15541551
/// close channel with their commitment transaction after a substantial amount of time. Best
15551552
/// may be to contact the other node operator out-of-band to coordinate other options available
15561553
/// to you.
1557-
///
1558-
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
1559-
pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
1554+
pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Result<Vec<Transaction>, ()>
15601555
where L::Target: Logger {
15611556
let mut inner = self.inner.lock().unwrap();
15621557
let logger = WithChannelMonitor::from_impl(logger, &*inner);
@@ -1789,6 +1784,12 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
17891784
pub fn set_counterparty_payment_script(&self, script: ScriptBuf) {
17901785
self.inner.lock().unwrap().counterparty_payment_script = script;
17911786
}
1787+
1788+
#[cfg(test)]
1789+
pub fn do_signer_call<F: FnMut(&Signer) -> ()>(&self, mut f: F) {
1790+
let inner = self.inner.lock().unwrap();
1791+
f(&inner.onchain_tx_handler.signer);
1792+
}
17921793
}
17931794

17941795
impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
@@ -3462,16 +3463,19 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
34623463

34633464
fn get_latest_holder_commitment_txn<L: Deref>(
34643465
&mut self, logger: &WithChannelMonitor<L>,
3465-
) -> Vec<Transaction> where L::Target: Logger {
3466+
) -> Result<Vec<Transaction>, ()> where L::Target: Logger {
34663467
log_debug!(logger, "Getting signed latest holder commitment transaction!");
34673468
self.holder_tx_signed = true;
3468-
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
3469+
let commitment_tx = self.onchain_tx_handler.get_maybe_signed_holder_tx(&self.funding_redeemscript);
3470+
if commitment_tx.input.iter().any(|input| input.witness.is_empty()) {
3471+
return Err(());
3472+
}
34693473
let txid = commitment_tx.txid();
34703474
let mut holder_transactions = vec![commitment_tx];
34713475
// When anchor outputs are present, the HTLC transactions are only valid once the commitment
34723476
// transaction confirms.
34733477
if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
3474-
return holder_transactions;
3478+
return Ok(holder_transactions);
34753479
}
34763480
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
34773481
if let Some(vout) = htlc.0.transaction_output_index {
@@ -3488,15 +3492,18 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
34883492
// confirmed in the next block.
34893493
continue;
34903494
} else { None };
3491-
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
3492-
&::bitcoin::OutPoint { txid, vout }, &preimage) {
3493-
holder_transactions.push(htlc_tx);
3495+
if let Some(htlc_tx) = self.onchain_tx_handler.get_maybe_signed_htlc_tx(
3496+
&::bitcoin::OutPoint { txid, vout }, &preimage
3497+
) {
3498+
if !htlc_tx.input.iter().any(|input| input.witness.is_empty()) {
3499+
holder_transactions.push(htlc_tx);
3500+
}
34943501
}
34953502
}
34963503
}
34973504
// We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
34983505
// The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
3499-
holder_transactions
3506+
Ok(holder_transactions)
35003507
}
35013508

35023509
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
@@ -3521,9 +3528,12 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
35213528
continue;
35223529
}
35233530
} else { None };
3524-
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
3525-
&::bitcoin::OutPoint { txid, vout }, &preimage) {
3526-
holder_transactions.push(htlc_tx);
3531+
if let Some(htlc_tx) = self.onchain_tx_handler.get_maybe_signed_htlc_tx(
3532+
&::bitcoin::OutPoint { txid, vout }, &preimage
3533+
) {
3534+
if !htlc_tx.input.iter().any(|input| input.witness.is_empty()) {
3535+
holder_transactions.push(htlc_tx);
3536+
}
35273537
}
35283538
}
35293539
}

lightning/src/chain/onchaintx.rs

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -497,9 +497,13 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
497497
}
498498
match claim {
499499
OnchainClaim::Tx(tx) => {
500-
let log_start = if bumped_feerate { "Broadcasting RBF-bumped" } else { "Rebroadcasting" };
501-
log_info!(logger, "{} onchain {}", log_start, log_tx!(tx));
502-
broadcaster.broadcast_transactions(&[&tx]);
500+
if tx.input.iter().any(|input| input.witness.is_empty()) {
501+
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.txid());
502+
} else {
503+
let log_start = if bumped_feerate { "Broadcasting RBF-bumped" } else { "Rebroadcasting" };
504+
log_info!(logger, "{} onchain {}", log_start, log_tx!(tx));
505+
broadcaster.broadcast_transactions(&[&tx]);
506+
}
503507
},
504508
OnchainClaim::Event(event) => {
505509
let log_start = if bumped_feerate { "Yielding fee-bumped" } else { "Replaying" };
@@ -636,8 +640,8 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
636640
let commitment_tx_feerate_sat_per_1000_weight =
637641
compute_feerate_sat_per_1000_weight(fee_sat, tx.weight().to_wu());
638642
if commitment_tx_feerate_sat_per_1000_weight >= package_target_feerate_sat_per_1000_weight {
639-
log_debug!(logger, "Pre-signed {} already has feerate {} sat/kW above required {} sat/kW",
640-
log_tx!(tx), commitment_tx_feerate_sat_per_1000_weight,
643+
log_debug!(logger, "Pre-signed commitment {} already has feerate {} sat/kW above required {} sat/kW",
644+
tx.txid(), commitment_tx_feerate_sat_per_1000_weight,
641645
package_target_feerate_sat_per_1000_weight);
642646
return Some((new_timer, 0, OnchainClaim::Tx(tx.clone())));
643647
}
@@ -776,8 +780,12 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
776780
// `OnchainClaim`.
777781
let claim_id = match claim {
778782
OnchainClaim::Tx(tx) => {
779-
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
780-
broadcaster.broadcast_transactions(&[&tx]);
783+
if tx.input.iter().any(|input| input.witness.is_empty()) {
784+
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.txid());
785+
} else {
786+
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx));
787+
broadcaster.broadcast_transactions(&[&tx]);
788+
}
781789
ClaimId(tx.txid().to_byte_array())
782790
},
783791
OnchainClaim::Event(claim_event) => {
@@ -969,8 +977,13 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
969977
) {
970978
match bump_claim {
971979
OnchainClaim::Tx(bump_tx) => {
972-
log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx));
973-
broadcaster.broadcast_transactions(&[&bump_tx]);
980+
if bump_tx.input.iter().any(|input| input.witness.is_empty()) {
981+
log_info!(logger, "Waiting for signature of RBF-bumped unsigned onchain transaction {}",
982+
bump_tx.txid());
983+
} else {
984+
log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx));
985+
broadcaster.broadcast_transactions(&[&bump_tx]);
986+
}
974987
},
975988
OnchainClaim::Event(claim_event) => {
976989
log_info!(logger, "Yielding RBF-bumped onchain event to spend inputs {:?}", request.outpoints());
@@ -1052,8 +1065,12 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
10521065
request.set_feerate(new_feerate);
10531066
match bump_claim {
10541067
OnchainClaim::Tx(bump_tx) => {
1055-
log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
1056-
broadcaster.broadcast_transactions(&[&bump_tx]);
1068+
if bump_tx.input.iter().any(|input| input.witness.is_empty()) {
1069+
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", bump_tx.txid());
1070+
} else {
1071+
log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx));
1072+
broadcaster.broadcast_transactions(&[&bump_tx]);
1073+
}
10571074
},
10581075
OnchainClaim::Event(claim_event) => {
10591076
log_info!(logger, "Yielding onchain event after reorg to spend inputs {:?}", request.outpoints());
@@ -1106,13 +1123,10 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
11061123
&self.holder_commitment.trust().built_transaction().transaction
11071124
}
11081125

1109-
//TODO: getting lastest holder transactions should be infallible and result in us "force-closing the channel", but we may
1110-
// have empty holder commitment transaction if a ChannelMonitor is asked to force-close just after OutboundV1Channel::get_funding_created,
1111-
// before providing a initial commitment transaction. For outbound channel, init ChannelMonitor at Channel::funding_signed, there is nothing
1112-
// to monitor before.
1113-
pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction {
1114-
let sig = self.signer.sign_holder_commitment(&self.holder_commitment, &self.secp_ctx).expect("signing holder commitment");
1115-
self.holder_commitment.add_holder_sig(funding_redeemscript, sig)
1126+
pub(crate) fn get_maybe_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction {
1127+
self.signer.sign_holder_commitment(&self.holder_commitment, &self.secp_ctx)
1128+
.map(|sig| self.holder_commitment.add_holder_sig(funding_redeemscript, sig))
1129+
.unwrap_or_else(|_| self.get_unsigned_holder_commitment_tx().clone())
11161130
}
11171131

11181132
#[cfg(any(test, feature="unsafe_revoked_tx_signing"))]
@@ -1121,7 +1135,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
11211135
self.holder_commitment.add_holder_sig(funding_redeemscript, sig)
11221136
}
11231137

1124-
pub(crate) fn get_fully_signed_htlc_tx(&mut self, outp: &::bitcoin::OutPoint, preimage: &Option<PaymentPreimage>) -> Option<Transaction> {
1138+
pub(crate) fn get_maybe_signed_htlc_tx(&mut self, outp: &::bitcoin::OutPoint, preimage: &Option<PaymentPreimage>) -> Option<Transaction> {
11251139
let get_signed_htlc_tx = |holder_commitment: &HolderCommitmentTransaction| {
11261140
let trusted_tx = holder_commitment.trust();
11271141
if trusted_tx.txid() != outp.txid {
@@ -1149,10 +1163,11 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
11491163
preimage: preimage.clone(),
11501164
counterparty_sig: counterparty_htlc_sig.clone(),
11511165
};
1152-
let htlc_sig = self.signer.sign_holder_htlc_transaction(&htlc_tx, 0, &htlc_descriptor, &self.secp_ctx).unwrap();
1153-
htlc_tx.input[0].witness = trusted_tx.build_htlc_input_witness(
1154-
htlc_idx, &counterparty_htlc_sig, &htlc_sig, preimage,
1155-
);
1166+
if let Ok(htlc_sig) = self.signer.sign_holder_htlc_transaction(&htlc_tx, 0, &htlc_descriptor, &self.secp_ctx) {
1167+
htlc_tx.input[0].witness = trusted_tx.build_htlc_input_witness(
1168+
htlc_idx, &counterparty_htlc_sig, &htlc_sig, preimage,
1169+
);
1170+
}
11561171
Some(htlc_tx)
11571172
};
11581173

lightning/src/chain/package.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,10 +637,10 @@ impl PackageSolvingData {
637637
match self {
638638
PackageSolvingData::HolderHTLCOutput(ref outp) => {
639639
debug_assert!(!outp.channel_type_features.supports_anchors_zero_fee_htlc_tx());
640-
return onchain_handler.get_fully_signed_htlc_tx(outpoint, &outp.preimage);
640+
onchain_handler.get_maybe_signed_htlc_tx(outpoint, &outp.preimage)
641641
}
642642
PackageSolvingData::HolderFundingOutput(ref outp) => {
643-
return Some(onchain_handler.get_fully_signed_holder_tx(&outp.funding_redeemscript));
643+
Some(onchain_handler.get_maybe_signed_holder_tx(&outp.funding_redeemscript))
644644
}
645645
_ => { panic!("API Error!"); }
646646
}

0 commit comments

Comments
 (0)