Merge pull request #2606 from wpaulino/anchors-counterparty-htlc-claim-sequence

Use correct input sequence for HTLC claims from counterparty commitments
This commit is contained in:
Matt Corallo 2023-09-28 16:32:18 +00:00 committed by GitHub
commit 336d815dd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 23 deletions

View file

@ -551,6 +551,32 @@ impl PackageSolvingData {
_ => { mem::discriminant(self) == mem::discriminant(&input) }
}
}
fn as_tx_input(&self, previous_output: BitcoinOutPoint) -> TxIn {
let sequence = match self {
PackageSolvingData::RevokedOutput(_) => Sequence::ENABLE_RBF_NO_LOCKTIME,
PackageSolvingData::RevokedHTLCOutput(_) => Sequence::ENABLE_RBF_NO_LOCKTIME,
PackageSolvingData::CounterpartyOfferedHTLCOutput(outp) => if outp.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
Sequence::from_consensus(1)
} else {
Sequence::ENABLE_RBF_NO_LOCKTIME
},
PackageSolvingData::CounterpartyReceivedHTLCOutput(outp) => if outp.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
Sequence::from_consensus(1)
} else {
Sequence::ENABLE_RBF_NO_LOCKTIME
},
_ => {
debug_assert!(false, "This should not be reachable by 'untractable' or 'malleable with external funding' packages");
Sequence::ENABLE_RBF_NO_LOCKTIME
},
};
TxIn {
previous_output,
script_sig: Script::new(),
sequence,
witness: Witness::new(),
}
}
fn finalize_input<Signer: WriteableEcdsaChannelSigner>(&self, bumped_tx: &mut Transaction, i: usize, onchain_handler: &mut OnchainTxHandler<Signer>) -> bool {
match self {
PackageSolvingData::RevokedOutput(ref outp) => {
@ -895,13 +921,8 @@ impl PackageTemplate {
value,
}],
};
for (outpoint, _) in self.inputs.iter() {
bumped_tx.input.push(TxIn {
previous_output: *outpoint,
script_sig: Script::new(),
sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
witness: Witness::new(),
});
for (outpoint, outp) in self.inputs.iter() {
bumped_tx.input.push(outp.as_tx_input(*outpoint));
}
for (i, (outpoint, out)) in self.inputs.iter().enumerate() {
log_debug!(logger, "Adding claiming input for outpoint {}:{}", outpoint.txid, outpoint.vout);

View file

@ -1867,23 +1867,35 @@ fn test_yield_anchors_events() {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config), Some(anchors_config)]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let chan_id = create_announced_chan_between_nodes_with_value(
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(
&nodes, 0, 1, 1_000_000, 500_000_000
).2;
route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[1], &[&nodes[0]], 1_000_000);
);
let (payment_preimage_1, payment_hash_1, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
let (payment_preimage_2, payment_hash_2, ..) = route_payment(&nodes[1], &[&nodes[0]], 2_000_000);
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
*nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
check_closed_broadcast!(&nodes[0], true);
assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
connect_blocks(&nodes[1], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
{
let txn = nodes[1].tx_broadcaster.txn_broadcast();
assert_eq!(txn.len(), 1);
check_spends!(txn[0], funding_tx);
}
get_monitor!(nodes[0], chan_id).provide_payment_preimage(
&payment_hash, &payment_preimage, &node_cfgs[0].tx_broadcaster,
&payment_hash_2, &payment_preimage_2, &node_cfgs[0].tx_broadcaster,
&LowerBoundedFeeEstimator::new(node_cfgs[0].fee_estimator), &nodes[0].logger
);
get_monitor!(nodes[1], chan_id).provide_payment_preimage(
&payment_hash_1, &payment_preimage_1, &node_cfgs[0].tx_broadcaster,
&LowerBoundedFeeEstimator::new(node_cfgs[1].fee_estimator), &nodes[1].logger
);
let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
assert_eq!(holder_events.len(), 1);
@ -1904,27 +1916,50 @@ fn test_yield_anchors_events() {
assert_eq!(txn.len(), 2);
let anchor_tx = txn.pop().unwrap();
let commitment_tx = txn.pop().unwrap();
check_spends!(commitment_tx, funding_tx);
check_spends!(anchor_tx, coinbase_tx, commitment_tx);
(commitment_tx, anchor_tx)
},
_ => panic!("Unexpected event"),
};
assert_eq!(commitment_tx.output[2].value, 1_000); // HTLC A -> B
assert_eq!(commitment_tx.output[3].value, 2_000); // HTLC B -> A
mine_transactions(&nodes[0], &[&commitment_tx, &anchor_tx]);
check_added_monitors!(nodes[0], 1);
mine_transactions(&nodes[1], &[&commitment_tx, &anchor_tx]);
check_added_monitors!(nodes[1], 1);
{
let mut txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
assert_eq!(txn.len(), if nodes[1].connect_style.borrow().updates_best_block_first() { 3 } else { 2 });
let htlc_preimage_tx = txn.pop().unwrap();
assert_eq!(htlc_preimage_tx.input.len(), 1);
assert_eq!(htlc_preimage_tx.input[0].previous_output.vout, 3);
check_spends!(htlc_preimage_tx, commitment_tx);
let htlc_timeout_tx = txn.pop().unwrap();
assert_eq!(htlc_timeout_tx.input.len(), 1);
assert_eq!(htlc_timeout_tx.input[0].previous_output.vout, 2);
check_spends!(htlc_timeout_tx, commitment_tx);
if let Some(commitment_tx) = txn.pop() {
check_spends!(commitment_tx, funding_tx);
}
}
let mut holder_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
// Certain block `ConnectStyle`s cause an extra `ChannelClose` event to be emitted since the
// best block is updated before the confirmed transactions are notified.
match *nodes[0].connect_style.borrow() {
ConnectStyle::BestBlockFirst|ConnectStyle::BestBlockFirstReorgsOnlyTip|ConnectStyle::BestBlockFirstSkippingBlocks => {
if nodes[0].connect_style.borrow().updates_best_block_first() {
assert_eq!(holder_events.len(), 3);
if let Event::BumpTransaction(BumpTransactionEvent::ChannelClose { .. }) = holder_events.remove(0) {}
else { panic!("unexpected event"); }
},
_ => assert_eq!(holder_events.len(), 2),
};
} else {
assert_eq!(holder_events.len(), 2);
}
let mut htlc_txs = Vec::with_capacity(2);
for event in holder_events {
match event {
@ -1958,6 +1993,9 @@ fn test_yield_anchors_events() {
// Clear the remaining events as they're not relevant to what we're testing.
nodes[0].node.get_and_clear_pending_events();
nodes[1].node.get_and_clear_pending_events();
nodes[0].node.get_and_clear_pending_msg_events();
nodes[1].node.get_and_clear_pending_msg_events();
}
#[test]