Skip to content

Commit d3bc90d

Browse files
committed
Use correct input sequence for HTLC claims from counterparty commitments
HTLC outputs, like the `to_remote` output, in commitment transactions with anchor outputs also have an additional `1 CSV` constraint on the counterparty. When spending such outputs, their corresponding input needs to have their sequence set to 1. This was done for HTLC claims from holder commitments, but unfortunately not for counterparty commitments as we were lacking test coverage.
1 parent 1ac53ed commit d3bc90d

File tree

2 files changed

+79
-23
lines changed

2 files changed

+79
-23
lines changed

lightning/src/chain/package.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,29 @@ impl PackageSolvingData {
551551
_ => { mem::discriminant(self) == mem::discriminant(&input) }
552552
}
553553
}
554+
fn as_tx_input(&self, previous_output: BitcoinOutPoint) -> TxIn {
555+
let sequence = match self {
556+
PackageSolvingData::RevokedOutput(_) => Sequence::ENABLE_RBF_NO_LOCKTIME,
557+
PackageSolvingData::RevokedHTLCOutput(_) => Sequence::ENABLE_RBF_NO_LOCKTIME,
558+
PackageSolvingData::CounterpartyOfferedHTLCOutput(outp) => if outp.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
559+
Sequence::from_consensus(1)
560+
} else {
561+
Sequence::ENABLE_RBF_NO_LOCKTIME
562+
},
563+
PackageSolvingData::CounterpartyReceivedHTLCOutput(outp) => if outp.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
564+
Sequence::from_consensus(1)
565+
} else {
566+
Sequence::ENABLE_RBF_NO_LOCKTIME
567+
},
568+
_ => { panic!("API Error!"); }
569+
};
570+
TxIn {
571+
previous_output,
572+
script_sig: Script::new(),
573+
sequence,
574+
witness: Witness::new(),
575+
}
576+
}
554577
fn finalize_input<Signer: WriteableEcdsaChannelSigner>(&self, bumped_tx: &mut Transaction, i: usize, onchain_handler: &mut OnchainTxHandler<Signer>) -> bool {
555578
match self {
556579
PackageSolvingData::RevokedOutput(ref outp) => {
@@ -895,13 +918,8 @@ impl PackageTemplate {
895918
value,
896919
}],
897920
};
898-
for (outpoint, _) in self.inputs.iter() {
899-
bumped_tx.input.push(TxIn {
900-
previous_output: *outpoint,
901-
script_sig: Script::new(),
902-
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
903-
witness: Witness::new(),
904-
});
921+
for (outpoint, outp) in self.inputs.iter() {
922+
bumped_tx.input.push(outp.as_tx_input(*outpoint));
905923
}
906924
for (i, (outpoint, out)) in self.inputs.iter().enumerate() {
907925
log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);

lightning/src/ln/monitor_tests.rs

+54-16
Original file line numberDiff line numberDiff line change
@@ -1867,23 +1867,35 @@ fn test_yield_anchors_events() {
18671867
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config), Some(anchors_config)]);
18681868
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
18691869

1870-
let chan_id = create_announced_chan_between_nodes_with_value(
1870+
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(
18711871
&nodes, 0, 1, 1_000_000, 500_000_000
1872-
).2;
1873-
route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
1874-
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[1], &[&nodes[0]], 1_000_000);
1872+
);
1873+
let (payment_preimage_1, payment_hash_1, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
1874+
let (payment_preimage_2, payment_hash_2, ..) = route_payment(&nodes[1], &[&nodes[0]], 2_000_000);
18751875

18761876
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
1877+
assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
18771878

18781879
*nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
1880+
18791881
connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
1880-
check_closed_broadcast!(&nodes[0], true);
1881-
assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
1882+
assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
1883+
1884+
connect_blocks(&nodes[1], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
1885+
{
1886+
let txn = nodes[1].tx_broadcaster.txn_broadcast();
1887+
assert_eq!(txn.len(), 1);
1888+
check_spends!(txn[0], funding_tx);
1889+
}
18821890

18831891
get_monitor!(nodes[0], chan_id).provide_payment_preimage(
1884-
&payment_hash, &payment_preimage, &node_cfgs[0].tx_broadcaster,
1892+
&payment_hash_2, &payment_preimage_2, &node_cfgs[0].tx_broadcaster,
18851893
&LowerBoundedFeeEstimator::new(node_cfgs[0].fee_estimator), &nodes[0].logger
18861894
);
1895+
get_monitor!(nodes[1], chan_id).provide_payment_preimage(
1896+
&payment_hash_1, &payment_preimage_1, &node_cfgs[0].tx_broadcaster,
1897+
&LowerBoundedFeeEstimator::new(node_cfgs[1].fee_estimator), &nodes[1].logger
1898+
);
18871899

18881900
let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
18891901
assert_eq!(holder_events.len(), 1);
@@ -1904,27 +1916,50 @@ fn test_yield_anchors_events() {
19041916
assert_eq!(txn.len(), 2);
19051917
let anchor_tx = txn.pop().unwrap();
19061918
let commitment_tx = txn.pop().unwrap();
1919+
check_spends!(commitment_tx, funding_tx);
19071920
check_spends!(anchor_tx, coinbase_tx, commitment_tx);
19081921
(commitment_tx, anchor_tx)
19091922
},
19101923
_ => panic!("Unexpected event"),
19111924
};
19121925

1926+
assert_eq!(commitment_tx.output[2].value, 1_000); // HTLC A -> B
1927+
assert_eq!(commitment_tx.output[3].value, 2_000); // HTLC B -> A
1928+
19131929
mine_transactions(&nodes[0], &[&commitment_tx, &anchor_tx]);
19141930
check_added_monitors!(nodes[0], 1);
1931+
mine_transactions(&nodes[1], &[&commitment_tx, &anchor_tx]);
1932+
check_added_monitors!(nodes[1], 1);
1933+
1934+
{
1935+
let mut txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
1936+
assert_eq!(txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
1937+
1938+
let htlc_preimage_tx = txn.pop().unwrap();
1939+
assert_eq!(htlc_preimage_tx.input.len(), 1);
1940+
assert_eq!(htlc_preimage_tx.input[0].previous_output.vout, 3);
1941+
check_spends!(htlc_preimage_tx, commitment_tx);
1942+
1943+
let htlc_timeout_tx = txn.pop().unwrap();
1944+
assert_eq!(htlc_timeout_tx.input.len(), 1);
1945+
assert_eq!(htlc_timeout_tx.input[0].previous_output.vout, 2);
1946+
check_spends!(htlc_timeout_tx, commitment_tx);
1947+
1948+
if let Some(commitment_tx) = txn.pop() {
1949+
check_spends!(commitment_tx, funding_tx);
1950+
}
1951+
}
19151952

19161953
let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
19171954
// Certain block `ConnectStyle`s cause an extra `ChannelClose` event to be emitted since the
19181955
// best block is updated before the confirmed transactions are notified.
1919-
match *nodes[0].connect_style.borrow() {
1920-
ConnectStyle::BestBlockFirst|ConnectStyle::BestBlockFirstReorgsOnlyTip|ConnectStyle::BestBlockFirstSkippingBlocks => {
1921-
assert_eq!(holder_events.len(), 3);
1922-
if let Event::BumpTransaction(BumpTransactionEvent::ChannelClose { .. }) = holder_events.remove(0) {}
1923-
else { panic!("unexpected event"); }
1924-
1925-
},
1926-
_ => assert_eq!(holder_events.len(), 2),
1927-
};
1956+
if nodes[0].connect_style.borrow().updates_best_block_first() {
1957+
assert_eq!(holder_events.len(), 3);
1958+
if let Event::BumpTransaction(BumpTransactionEvent::ChannelClose { .. }) = holder_events.remove(0) {}
1959+
else { panic!("unexpected event"); }
1960+
} else {
1961+
assert_eq!(holder_events.len(), 2);
1962+
}
19281963
let mut htlc_txs = Vec::with_capacity(2);
19291964
for event in holder_events {
19301965
match event {
@@ -1958,6 +1993,9 @@ fn test_yield_anchors_events() {
19581993

19591994
// Clear the remaining events as they're not relevant to what we're testing.
19601995
nodes[0].node.get_and_clear_pending_events();
1996+
nodes[1].node.get_and_clear_pending_events();
1997+
nodes[0].node.get_and_clear_pending_msg_events();
1998+
nodes[1].node.get_and_clear_pending_msg_events();
19611999
}
19622000

19632001
#[test]

0 commit comments

Comments
 (0)