Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix matching of second-stage HTLC claim in get_htlc_balance #2610

Merged
merged 9 commits into from
Sep 29, 2023
17 changes: 14 additions & 3 deletions lightning/src/chain/channelmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1751,7 +1751,19 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
},
OnchainEvent::MaturingOutput {
descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) }
if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx => {
if event.transaction.as_ref().map(|tx| tx.input.iter().enumerate()
.any(|(input_idx, inp)|
Some(inp.previous_output.txid) == confirmed_txid &&
inp.previous_output.vout == htlc_commitment_tx_output_idx &&
// A maturing output for an HTLC claim will always be at the same
// index as the HTLC input. This is true pre-anchors, as there's
// only 1 input and 1 output. This is also true post-anchors,
// because we have a SIGHASH_SINGLE|ANYONECANPAY signature from our
// channel counterparty.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be canonical this is a property of the transaction signature bip143 digest algorithm where the sha_single_output is computed from the index of the spent input. This is also true for bip341 digest algorithm, however if transaction digest algorithm computation of sighash flags change in the future, we would have to update this code in consequence (and indeed more complicated sighash flags have been proposed in the past).

descriptor.outpoint.index as usize == input_idx
))
.unwrap_or(false)
=> {
debug_assert!(holder_delayed_output_pending.is_none());
holder_delayed_output_pending = Some(event.confirmation_threshold());
},
Expand Down Expand Up @@ -1892,8 +1904,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
/// confirmations on the claim transaction.
///
/// Note that for `ChannelMonitors` which track a channel which went on-chain with versions of
/// LDK prior to 0.0.111, balances may not be fully captured if our counterparty broadcasted
/// a revoked state.
/// LDK prior to 0.0.111, not all or excess balances may be included.
///
/// See [`Balance`] for additional details on the types of claimable balances which
/// may be returned here and their meanings.
Expand Down
20 changes: 18 additions & 2 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::sign::EntropySource;
use crate::chain::channelmonitor::ChannelMonitor;
use crate::chain::transaction::OutPoint;
use crate::events::{ClaimedHTLC, ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
use crate::events::bump_transaction::{BumpTransactionEventHandler, Wallet, WalletSource};
use crate::events::bump_transaction::{BumpTransactionEvent, BumpTransactionEventHandler, Wallet, WalletSource};
use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
use crate::ln::channelmanager::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA};
use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
Expand Down Expand Up @@ -1504,6 +1504,21 @@ macro_rules! check_closed_event {
}
}

pub fn handle_bump_htlc_event(node: &Node, count: usize) {
let events = node.chain_monitor.chain_monitor.get_and_clear_pending_events();
assert_eq!(events.len(), count);
for event in events {
match event {
Event::BumpTransaction(bump_event) => {
if let BumpTransactionEvent::HTLCResolution { .. } = &bump_event {}
else { panic!(); }
node.bump_tx_handler.handle_event(&bump_event);
},
_ => panic!(),
}
}
}

pub fn close_channel<'a, 'b, 'c>(outbound_node: &Node<'a, 'b, 'c>, inbound_node: &Node<'a, 'b, 'c>, channel_id: &ChannelId, funding_tx: Transaction, close_inbound_first: bool) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, Transaction) {
let (node_a, broadcaster_a, struct_a) = if close_inbound_first { (&inbound_node.node, &inbound_node.tx_broadcaster, inbound_node) } else { (&outbound_node.node, &outbound_node.tx_broadcaster, outbound_node) };
let (node_b, broadcaster_b, struct_b) = if close_inbound_first { (&outbound_node.node, &outbound_node.tx_broadcaster, outbound_node) } else { (&inbound_node.node, &inbound_node.tx_broadcaster, inbound_node) };
Expand Down Expand Up @@ -2780,7 +2795,8 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
}

// Note that the following only works for CLTV values up to 128
pub const ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 137; //Here we have a diff due to HTLC CLTV expiry being < 2^15 in test
pub const ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 137; // Here we have a diff due to HTLC CLTV expiry being < 2^15 in test
pub const ACCEPTED_HTLC_SCRIPT_WEIGHT_ANCHORS: usize = 140; // Here we have a diff due to HTLC CLTV expiry being < 2^15 in test

#[derive(PartialEq)]
pub enum HTLCType { NONE, TIMEOUT, SUCCESS }
Expand Down
Loading
Loading