Skip to content

Commit 1d65ab8

Browse files
committed
Remove panics for sign_holder_commitment_and_htlcs
1 parent c91debb commit 1d65ab8

File tree

7 files changed

+112
-58
lines changed

7 files changed

+112
-58
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use crate::chain;
4343
use crate::chain::{BestBlock, WatchedOutput};
4444
use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
4545
use crate::chain::transaction::{OutPoint, TransactionData};
46+
use crate::sign::errors::SigningError;
4647
use crate::sign::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, WriteableEcdsaChannelSigner, SignerProvider, EntropySource};
4748
use crate::chain::onchaintx::{ClaimEvent, OnchainTxHandler};
4849
use crate::chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput};
@@ -1482,21 +1483,16 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
14821483
self.inner.lock().unwrap().counterparty_node_id
14831484
}
14841485

1485-
/// Used by [`ChannelManager`] deserialization to broadcast the latest holder state if its copy
1486-
/// of the channel state was out-of-date.
1487-
///
1488-
/// You may also use this to broadcast the latest local commitment transaction, either because
1486+
/// You may use this to broadcast the latest local commitment transaction, either because
14891487
/// a monitor update failed or because we've fallen behind (i.e. we've received proof that our
14901488
/// counterparty side knows a revocation secret we gave them that they shouldn't know).
14911489
///
1492-
/// Broadcasting these transactions in the second case is UNSAFE, as they allow counterparty
1490+
/// Broadcasting these transactions in this manner is UNSAFE, as they allow counterparty
14931491
/// side to punish you. Nevertheless you may want to broadcast them if counterparty doesn't
14941492
/// close channel with their commitment transaction after a substantial amount of time. Best
14951493
/// may be to contact the other node operator out-of-band to coordinate other options available
14961494
/// to you.
1497-
///
1498-
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
1499-
pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
1495+
pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Result<Vec<Transaction>, SigningError>
15001496
where L::Target: Logger {
15011497
self.inner.lock().unwrap().get_latest_holder_commitment_txn(logger)
15021498
}
@@ -1505,7 +1501,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
15051501
/// to bypass HolderCommitmentTransaction state update lockdown after signature and generate
15061502
/// revoked commitment transaction.
15071503
#[cfg(any(test, feature = "unsafe_revoked_tx_signing"))]
1508-
pub fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
1504+
pub fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Result<Vec<Transaction>, SigningError>
15091505
where L::Target: Logger {
15101506
self.inner.lock().unwrap().unsafe_get_latest_holder_commitment_txn(logger)
15111507
}
@@ -2515,17 +2511,53 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
25152511
}
25162512
}
25172513

2518-
pub(crate) fn broadcast_latest_holder_commitment_txn<B: Deref, L: Deref>(&mut self, broadcaster: &B, logger: &L)
2514+
fn generate_claimable_outpoints_and_watch_outputs(&mut self) -> (Vec<PackageTemplate>, Vec<TransactionOutputs>) {
2515+
let funding_outp = HolderFundingOutput::build(
2516+
self.funding_redeemscript.clone(),
2517+
self.channel_value_satoshis,
2518+
self.onchain_tx_handler.channel_type_features().clone()
2519+
);
2520+
let commitment_package = PackageTemplate::build_package(
2521+
self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
2522+
PackageSolvingData::HolderFundingOutput(funding_outp),
2523+
self.best_block.height(), self.best_block.height()
2524+
);
2525+
let mut claimable_outpoints = vec![commitment_package];
2526+
self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
2527+
// Although we aren't signing the transaction directly here, the transaction will be signed
2528+
// in the claim that is queued to OnchainTxHandler. We set holder_tx_signed here to reject
2529+
// new channel updates.
2530+
self.holder_tx_signed = true;
2531+
let mut watch_outputs = Vec::new();
2532+
// We can't broadcast our HTLC transactions while the commitment transaction is
2533+
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
2534+
// `transactions_confirmed`.
2535+
if !self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
2536+
// Because we're broadcasting a commitment transaction, we should construct the package
2537+
// assuming it gets confirmed in the next block. Sadly, we have code which considers
2538+
// "not yet confirmed" things as discardable, so we cannot do that here.
2539+
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(
2540+
&self.current_holder_commitment_tx, self.best_block.height()
2541+
);
2542+
let unsigned_commitment_tx = self.onchain_tx_handler.get_unsigned_holder_commitment_tx();
2543+
let new_outputs = self.get_broadcasted_holder_watch_outputs(
2544+
&self.current_holder_commitment_tx, &unsigned_commitment_tx
2545+
);
2546+
if !new_outputs.is_empty() {
2547+
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
2548+
}
2549+
claimable_outpoints.append(&mut new_outpoints);
2550+
}
2551+
(claimable_outpoints, watch_outputs)
2552+
}
2553+
2554+
pub(crate) fn queue_latest_holder_commitment_txn_for_broadcast<B: Deref, F: Deref, L: Deref>(&mut self, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L)
25192555
where B::Target: BroadcasterInterface,
2520-
L::Target: Logger,
2556+
F::Target: FeeEstimator,
2557+
L::Target: Logger,
25212558
{
2522-
let commit_txs = self.get_latest_holder_commitment_txn(logger);
2523-
let mut txs = vec![];
2524-
for tx in commit_txs.iter() {
2525-
log_info!(logger, "Broadcasting local {}", log_tx!(tx));
2526-
txs.push(tx);
2527-
}
2528-
broadcaster.broadcast_transactions(&txs);
2559+
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs();
2560+
self.onchain_tx_handler.update_claims_view_from_requests(claimable_outpoints, self.best_block.height(), self.best_block.height(), broadcaster, fee_estimator, logger);
25292561
self.pending_monitor_events.push(MonitorEvent::HolderForceClosed(self.funding_info.0));
25302562
}
25312563

@@ -2614,26 +2646,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
26142646
log_trace!(logger, "Avoiding commitment broadcast, already detected confirmed spend onchain");
26152647
continue;
26162648
}
2617-
self.broadcast_latest_holder_commitment_txn(broadcaster, logger);
2618-
// If the channel supports anchor outputs, we'll need to emit an external
2619-
// event to be consumed such that a child transaction is broadcast with a
2620-
// high enough feerate for the parent commitment transaction to confirm.
2621-
if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
2622-
let funding_output = HolderFundingOutput::build(
2623-
self.funding_redeemscript.clone(), self.channel_value_satoshis,
2624-
self.onchain_tx_handler.channel_type_features().clone(),
2625-
);
2626-
let best_block_height = self.best_block.height();
2627-
let commitment_package = PackageTemplate::build_package(
2628-
self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
2629-
PackageSolvingData::HolderFundingOutput(funding_output),
2630-
best_block_height, best_block_height
2631-
);
2632-
self.onchain_tx_handler.update_claims_view_from_requests(
2633-
vec![commitment_package], best_block_height, best_block_height,
2634-
broadcaster, &bounded_fee_estimator, logger,
2635-
);
2636-
}
2649+
self.queue_latest_holder_commitment_txn_for_broadcast(broadcaster, &bounded_fee_estimator, logger);
26372650
} else if !self.holder_tx_signed {
26382651
log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast");
26392652
log_error!(logger, " in channel monitor for channel {}!", &self.funding_info.0.to_channel_id());
@@ -3211,16 +3224,16 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32113224
}
32123225
}
32133226

3214-
pub fn get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
3227+
pub fn get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Result<Vec<Transaction>, SigningError> where L::Target: Logger {
32153228
log_debug!(logger, "Getting signed latest holder commitment transaction!");
32163229
self.holder_tx_signed = true;
3217-
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
3230+
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript)?;
32183231
let txid = commitment_tx.txid();
32193232
let mut holder_transactions = vec![commitment_tx];
32203233
// When anchor outputs are present, the HTLC transactions are only valid once the commitment
32213234
// transaction confirms.
32223235
if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
3223-
return holder_transactions;
3236+
return Ok(holder_transactions);
32243237
}
32253238
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
32263239
if let Some(vout) = htlc.0.transaction_output_index {
@@ -3245,20 +3258,20 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32453258
}
32463259
// 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.
32473260
// The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
3248-
holder_transactions
3261+
Ok(holder_transactions)
32493262
}
32503263

32513264
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
32523265
/// Note that this includes possibly-locktimed-in-the-future transactions!
3253-
fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
3266+
fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Result<Vec<Transaction>, SigningError> where L::Target: Logger {
32543267
log_debug!(logger, "Getting signed copy of latest holder commitment transaction!");
32553268
let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript);
32563269
let txid = commitment_tx.txid();
32573270
let mut holder_transactions = vec![commitment_tx];
32583271
// When anchor outputs are present, the HTLC transactions are only final once the commitment
32593272
// transaction confirms due to the CSV 1 encumberance.
32603273
if self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
3261-
return holder_transactions;
3274+
return Ok(holder_transactions);
32623275
}
32633276
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
32643277
if let Some(vout) = htlc.0.transaction_output_index {
@@ -3274,7 +3287,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32743287
}
32753288
}
32763289
}
3277-
holder_transactions
3290+
Ok(holder_transactions)
32783291
}
32793292

32803293
pub fn block_connected<B: Deref, F: Deref, L: Deref>(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L) -> Vec<TransactionOutputs>

lightning/src/chain/onchaintx.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use crate::ln::chan_utils::{self, ChannelTransactionParameters, HTLCOutputInComm
3030
use crate::chain::ClaimId;
3131
use crate::chain::chaininterface::{ConfirmationTarget, FeeEstimator, BroadcasterInterface, LowerBoundedFeeEstimator};
3232
use crate::chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER};
33+
use crate::sign::errors::SigningError;
3334
use crate::sign::WriteableEcdsaChannelSigner;
3435
use crate::chain::package::{PackageSolvingData, PackageTemplate};
3536
use crate::util::logger::Logger;
@@ -1131,10 +1132,12 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
11311132
// have empty holder commitment transaction if a ChannelMonitor is asked to force-close just after OutboundV1Channel::get_funding_created,
11321133
// before providing a initial commitment transaction. For outbound channel, init ChannelMonitor at Channel::funding_signed, there is nothing
11331134
// to monitor before.
1134-
pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction {
1135-
let (sig, htlc_sigs) = self.signer.sign_holder_commitment_and_htlcs(&self.holder_commitment, &self.secp_ctx).expect("signing holder commitment");
1135+
pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Result<Transaction, SigningError> {
1136+
let (sig, htlc_sigs) = self.signer.sign_holder_commitment_and_htlcs(
1137+
&self.holder_commitment, &self.secp_ctx
1138+
)?;
11361139
self.holder_htlc_sigs = Some(Self::extract_holder_sigs(&self.holder_commitment, htlc_sigs));
1137-
self.holder_commitment.add_holder_sig(funding_redeemscript, sig)
1140+
Ok(self.holder_commitment.add_holder_sig(funding_redeemscript, sig))
11381141
}
11391142

11401143
#[cfg(any(test, feature="unsafe_revoked_tx_signing"))]

lightning/src/chain/package.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment};
2525
use crate::ln::chan_utils;
2626
use crate::ln::msgs::DecodeError;
2727
use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
28+
use crate::sign::errors::SigningError;
2829
use crate::sign::WriteableEcdsaChannelSigner;
2930
use crate::chain::onchaintx::{ExternalHTLCClaim, OnchainTxHandler};
3031
use crate::util::logger::Logger;
@@ -613,7 +614,19 @@ impl PackageSolvingData {
613614
return onchain_handler.get_fully_signed_htlc_tx(outpoint, &outp.preimage);
614615
}
615616
PackageSolvingData::HolderFundingOutput(ref outp) => {
616-
return Some(onchain_handler.get_fully_signed_holder_tx(&outp.funding_redeemscript));
617+
match onchain_handler.get_fully_signed_holder_tx(&outp.funding_redeemscript) {
618+
Ok(tx) => {
619+
return Some(tx);
620+
},
621+
Err(e) => match e{
622+
SigningError::NotAvailable => {
623+
return None;
624+
},
625+
SigningError::PermanentFailure => {
626+
panic!("Failed to sign holder transaction!");
627+
},
628+
},
629+
}
617630
}
618631
_ => { panic!("API Error!"); }
619632
}

lightning/src/ln/functional_test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ macro_rules! get_monitor {
885885
macro_rules! get_local_commitment_txn {
886886
($node: expr, $channel_id: expr) => {
887887
{
888-
$crate::get_monitor!($node, $channel_id).unsafe_get_latest_holder_commitment_txn(&$node.logger)
888+
$crate::get_monitor!($node, $channel_id).unsafe_get_latest_holder_commitment_txn(&$node.logger).unwrap()
889889
}
890890
}
891891
}

lightning/src/sign/errors.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// This file is Copyright its original authors, visible in version control
2+
// history.
3+
//
4+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5+
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7+
// You may not use this file except in accordance with one or both of these
8+
// licenses.
9+
10+
//! Signing error types live here.
11+
12+
#[derive(Clone, Debug)]
13+
pub enum SigningError {
14+
/// The signature is not immediately available from the signer but will be
15+
/// provided later when the signer is online.
16+
NotAvailable,
17+
/// The signer failed permanently and we should attempt to close the
18+
/// channel.
19+
PermanentFailure,
20+
}

lightning/src/sign/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ use crate::util::atomic_counter::AtomicCounter;
5656
use crate::util::chacha20::ChaCha20;
5757
use crate::util::invoice::construct_invoice_preimage;
5858

59+
pub mod errors;
60+
5961
pub(crate) mod type_resolver;
6062

6163
/// Used as initial key material, to be expanded into multiple secret keys (but not to be used
@@ -446,14 +448,14 @@ pub trait EcdsaChannelSigner: ChannelSigner {
446448
/// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor
447449
// TODO: Document the things someone using this interface should enforce before signing.
448450
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction,
449-
secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()>;
451+
secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), errors::SigningError>;
450452
/// Same as [`sign_holder_commitment_and_htlcs`], but exists only for tests to get access to
451453
/// holder commitment transactions which will be broadcasted later, after the channel has moved
452454
/// on to a newer state. Thus, needs its own method as [`sign_holder_commitment_and_htlcs`] may
453455
/// enforce that we only ever get called once.
454456
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
455457
fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction,
456-
secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()>;
458+
secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), errors::SigningError>;
457459
/// Create a signature for the given input in a transaction spending an HTLC transaction output
458460
/// or a commitment transaction `to_local` output when our counterparty broadcasts an old state.
459461
///
@@ -1012,24 +1014,26 @@ impl EcdsaChannelSigner for InMemorySigner {
10121014
Ok(())
10131015
}
10141016

1015-
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
1017+
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), errors::SigningError> {
10161018
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
10171019
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
10181020
let trusted_tx = commitment_tx.trust();
10191021
let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx);
10201022
let channel_parameters = self.get_channel_parameters();
1021-
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?;
1023+
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)
1024+
.map_err(|_| errors::SigningError::PermanentFailure)?;
10221025
Ok((sig, htlc_sigs))
10231026
}
10241027

10251028
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
1026-
fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
1029+
fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), errors::SigningError> {
10271030
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
10281031
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
10291032
let trusted_tx = commitment_tx.trust();
10301033
let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx);
10311034
let channel_parameters = self.get_channel_parameters();
1032-
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?;
1035+
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)
1036+
.map_err(|_| errors::SigningError::PermanentFailure)?;
10331037
Ok((sig, htlc_sigs))
10341038
}
10351039

0 commit comments

Comments
 (0)