Skip to content

Commit 4828817

Browse files
committed
Use existing height timer to retry untractable packages
Untractable packages are those which cannot have their fees updated once signed, hence why they weren't retried. There's no harm in retrying these packages by simply re-broadcasting them though, as the fee market could have spontaneously spiked when we first broadcast it, leading to our transaction not propagating throughout node mempools unless broadcast manually.
1 parent 2e15df7 commit 4828817

File tree

7 files changed

+212
-105
lines changed

7 files changed

+212
-105
lines changed

lightning/src/chain/onchaintx.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
583583
None => return None,
584584
};
585585
if !cached_request.requires_external_funding() {
586-
return Some((None, 0, OnchainClaim::Tx(tx)));
586+
return Some((new_timer, 0, OnchainClaim::Tx(tx)));
587587
}
588588
#[cfg(anchors)]
589589
return inputs.find_map(|input| match input {

lightning/src/ln/functional_test_utils.rs

+32-20
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,20 @@ pub enum ConnectStyle {
137137
}
138138

139139
impl ConnectStyle {
140+
pub fn skips_blocks(&self) -> bool {
141+
match self {
142+
ConnectStyle::BestBlockFirst => false,
143+
ConnectStyle::BestBlockFirstSkippingBlocks => true,
144+
ConnectStyle::BestBlockFirstReorgsOnlyTip => true,
145+
ConnectStyle::TransactionsFirst => false,
146+
ConnectStyle::TransactionsFirstSkippingBlocks => true,
147+
ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks => true,
148+
ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks => true,
149+
ConnectStyle::TransactionsFirstReorgsOnlyTip => true,
150+
ConnectStyle::FullBlockViaListen => false,
151+
}
152+
}
153+
140154
fn random_style() -> ConnectStyle {
141155
#[cfg(feature = "std")] {
142156
use core::hash::{BuildHasher, Hasher};
@@ -164,12 +178,7 @@ impl ConnectStyle {
164178
}
165179

166180
pub fn connect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, depth: u32) -> BlockHash {
167-
let skip_intermediaries = match *node.connect_style.borrow() {
168-
ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks|
169-
ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks|ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks|
170-
ConnectStyle::BestBlockFirstReorgsOnlyTip|ConnectStyle::TransactionsFirstReorgsOnlyTip => true,
171-
_ => false,
172-
};
181+
let skip_intermediaries = node.connect_style.borrow().skips_blocks();
173182

174183
let height = node.best_block_info().1 + 1;
175184
let mut block = Block {
@@ -2535,6 +2544,8 @@ pub enum HTLCType { NONE, TIMEOUT, SUCCESS }
25352544
/// also fail.
25362545
pub fn test_txn_broadcast<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction), commitment_tx: Option<Transaction>, has_htlc_tx: HTLCType) -> Vec<Transaction> {
25372546
let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap();
2547+
let mut txn_seen = HashSet::new();
2548+
node_txn.retain(|tx| txn_seen.insert(tx.txid()));
25382549
assert!(node_txn.len() >= if commitment_tx.is_some() { 0 } else { 1 } + if has_htlc_tx == HTLCType::NONE { 0 } else { 1 });
25392550

25402551
let mut res = Vec::with_capacity(2);
@@ -2598,22 +2609,23 @@ pub fn test_revoked_htlc_claim_txn_broadcast<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>
25982609

25992610
pub fn check_preimage_claim<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, prev_txn: &Vec<Transaction>) -> Vec<Transaction> {
26002611
let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap();
2612+
let mut txn_seen = HashSet::new();
2613+
node_txn.retain(|tx| txn_seen.insert(tx.txid()));
26012614

2602-
assert!(node_txn.len() >= 1);
2603-
assert_eq!(node_txn[0].input.len(), 1);
26042615
let mut found_prev = false;
2605-
2606-
for tx in prev_txn {
2607-
if node_txn[0].input[0].previous_output.txid == tx.txid() {
2608-
check_spends!(node_txn[0], tx);
2609-
let mut iter = node_txn[0].input[0].witness.iter();
2610-
iter.next().expect("expected 3 witness items");
2611-
iter.next().expect("expected 3 witness items");
2612-
assert!(iter.next().expect("expected 3 witness items").len() > 106); // must spend an htlc output
2613-
assert_eq!(tx.input.len(), 1); // must spend a commitment tx
2614-
2615-
found_prev = true;
2616-
break;
2616+
for prev_tx in prev_txn {
2617+
for tx in &*node_txn {
2618+
if tx.input[0].previous_output.txid == prev_tx.txid() {
2619+
check_spends!(tx, prev_tx);
2620+
let mut iter = tx.input[0].witness.iter();
2621+
iter.next().expect("expected 3 witness items");
2622+
iter.next().expect("expected 3 witness items");
2623+
assert!(iter.next().expect("expected 3 witness items").len() > 106); // must spend an htlc output
2624+
assert_eq!(tx.input.len(), 1); // must spend a commitment tx
2625+
2626+
found_prev = true;
2627+
break;
2628+
}
26172629
}
26182630
}
26192631
assert!(found_prev);

lightning/src/ln/functional_tests.rs

+71-57
Original file line numberDiff line numberDiff line change
@@ -2390,8 +2390,8 @@ fn channel_monitor_network_test() {
23902390
}
23912391

23922392
#[test]
2393-
fn test_justice_tx() {
2394-
// Test justice txn built on revoked HTLC-Success tx, against both sides
2393+
fn test_justice_tx_htlc_timeout() {
2394+
// Test justice txn built on revoked HTLC-Timeout tx, against both sides
23952395
let mut alice_config = UserConfig::default();
23962396
alice_config.channel_handshake_config.announced_channel = true;
23972397
alice_config.channel_handshake_limits.force_announced_channel_preference = false;
@@ -2407,7 +2407,6 @@ fn test_justice_tx() {
24072407
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
24082408
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &user_cfgs);
24092409
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2410-
*nodes[0].connect_style.borrow_mut() = ConnectStyle::FullBlockViaListen;
24112410
// Create some new channels:
24122411
let chan_5 = create_announced_chan_between_nodes(&nodes, 0, 1);
24132412

@@ -2431,7 +2430,6 @@ fn test_justice_tx() {
24312430
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
24322431
assert_eq!(node_txn.len(), 1); // ChannelMonitor: penalty tx
24332432
assert_eq!(node_txn[0].input.len(), 2); // We should claim the revoked output and the HTLC output
2434-
24352433
check_spends!(node_txn[0], revoked_local_txn[0]);
24362434
node_txn.swap_remove(0);
24372435
}
@@ -2450,17 +2448,30 @@ fn test_justice_tx() {
24502448
test_revoked_htlc_claim_txn_broadcast(&nodes[1], node_txn[1].clone(), revoked_local_txn[0].clone());
24512449
}
24522450
get_announce_close_broadcast_events(&nodes, 0, 1);
2453-
24542451
assert_eq!(nodes[0].node.list_channels().len(), 0);
24552452
assert_eq!(nodes[1].node.list_channels().len(), 0);
2453+
}
24562454

2457-
// We test justice_tx build by A on B's revoked HTLC-Success tx
2455+
#[test]
2456+
fn test_justice_tx_htlc_success() {
2457+
// Test justice txn built on revoked HTLC-Success tx, against both sides
2458+
let mut alice_config = UserConfig::default();
2459+
alice_config.channel_handshake_config.announced_channel = true;
2460+
alice_config.channel_handshake_limits.force_announced_channel_preference = false;
2461+
alice_config.channel_handshake_config.our_to_self_delay = 6 * 24 * 5;
2462+
let mut bob_config = UserConfig::default();
2463+
bob_config.channel_handshake_config.announced_channel = true;
2464+
bob_config.channel_handshake_limits.force_announced_channel_preference = false;
2465+
bob_config.channel_handshake_config.our_to_self_delay = 6 * 24 * 3;
2466+
let user_cfgs = [Some(alice_config), Some(bob_config)];
2467+
let mut chanmon_cfgs = create_chanmon_cfgs(2);
2468+
chanmon_cfgs[0].keys_manager.disable_revocation_policy_check = true;
2469+
chanmon_cfgs[1].keys_manager.disable_revocation_policy_check = true;
2470+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2471+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &user_cfgs);
2472+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
24582473
// Create some new channels:
24592474
let chan_6 = create_announced_chan_between_nodes(&nodes, 0, 1);
2460-
{
2461-
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
2462-
node_txn.clear();
2463-
}
24642475

24652476
// A pending HTLC which will be revoked:
24662477
let payment_preimage_4 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
@@ -2638,8 +2649,7 @@ fn claim_htlc_outputs_single_tx() {
26382649
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
26392650
assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
26402651

2641-
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
2642-
assert_eq!(node_txn.len(), 7);
2652+
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcast();
26432653

26442654
// Check the pair local commitment and HTLC-timeout broadcast due to HTLC expiration
26452655
assert_eq!(node_txn[0].input.len(), 1);
@@ -2649,29 +2659,32 @@ fn claim_htlc_outputs_single_tx() {
26492659
assert_eq!(witness_script.len(), OFFERED_HTLC_SCRIPT_WEIGHT); //Spending an offered htlc output
26502660
check_spends!(node_txn[1], node_txn[0]);
26512661

2652-
// Justice transactions are indices 2-3-4
2662+
// Filter out any non justice transactions.
2663+
node_txn.retain(|tx| tx.input[0].previous_output.txid == revoked_local_txn[0].txid());
2664+
assert!(node_txn.len() > 3);
2665+
2666+
assert_eq!(node_txn[0].input.len(), 1);
2667+
assert_eq!(node_txn[1].input.len(), 1);
26532668
assert_eq!(node_txn[2].input.len(), 1);
2654-
assert_eq!(node_txn[3].input.len(), 1);
2655-
assert_eq!(node_txn[4].input.len(), 1);
26562669

2670+
check_spends!(node_txn[0], revoked_local_txn[0]);
2671+
check_spends!(node_txn[1], revoked_local_txn[0]);
26572672
check_spends!(node_txn[2], revoked_local_txn[0]);
2658-
check_spends!(node_txn[3], revoked_local_txn[0]);
2659-
check_spends!(node_txn[4], revoked_local_txn[0]);
26602673

26612674
let mut witness_lens = BTreeSet::new();
2675+
witness_lens.insert(node_txn[0].input[0].witness.last().unwrap().len());
2676+
witness_lens.insert(node_txn[1].input[0].witness.last().unwrap().len());
26622677
witness_lens.insert(node_txn[2].input[0].witness.last().unwrap().len());
2663-
witness_lens.insert(node_txn[3].input[0].witness.last().unwrap().len());
2664-
witness_lens.insert(node_txn[4].input[0].witness.last().unwrap().len());
26652678
assert_eq!(witness_lens.len(), 3);
26662679
assert_eq!(*witness_lens.iter().skip(0).next().unwrap(), 77); // revoked to_local
26672680
assert_eq!(*witness_lens.iter().skip(1).next().unwrap(), OFFERED_HTLC_SCRIPT_WEIGHT); // revoked offered HTLC
26682681
assert_eq!(*witness_lens.iter().skip(2).next().unwrap(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // revoked received HTLC
26692682

26702683
// Finally, mine the penalty transactions and check that we get an HTLC failure after
26712684
// ANTI_REORG_DELAY confirmations.
2685+
mine_transaction(&nodes[1], &node_txn[0]);
2686+
mine_transaction(&nodes[1], &node_txn[1]);
26722687
mine_transaction(&nodes[1], &node_txn[2]);
2673-
mine_transaction(&nodes[1], &node_txn[3]);
2674-
mine_transaction(&nodes[1], &node_txn[4]);
26752688
connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
26762689
expect_payment_failed!(nodes[1], payment_hash_2, false);
26772690
}
@@ -2970,25 +2983,20 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) {
29702983

29712984
// Broadcast timeout transaction by B on received output from C's commitment tx on B's chain
29722985
// Verify that B's ChannelManager is able to detect that HTLC is timeout by its own tx and react backward in consequence
2973-
connect_blocks(&nodes[1], 200 - nodes[2].best_block_info().1);
29742986
mine_transaction(&nodes[1], &commitment_tx[0]);
2975-
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
2976-
let timeout_tx;
2977-
{
2978-
let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
2979-
assert_eq!(node_txn.len(), 3); // 2 (local commitment tx + HTLC-timeout), 1 timeout tx
2980-
2981-
check_spends!(node_txn[2], commitment_tx[0]);
2982-
assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
2983-
2984-
check_spends!(node_txn[0], chan_2.3);
2985-
check_spends!(node_txn[1], node_txn[0]);
2986-
assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), 71);
2987-
assert_eq!(node_txn[1].clone().input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
2988-
2989-
timeout_tx = node_txn[2].clone();
2990-
node_txn.clear();
2991-
}
2987+
check_closed_event(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false);
2988+
connect_blocks(&nodes[1], 200 - nodes[2].best_block_info().1);
2989+
let timeout_tx = {
2990+
let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
2991+
if nodes[1].connect_style.borrow().skips_blocks() {
2992+
assert_eq!(txn.len(), 1);
2993+
} else {
2994+
assert_eq!(txn.len(), 2); // Extra rebroadcast of timeout transaction
2995+
}
2996+
check_spends!(txn[0], commitment_tx[0]);
2997+
assert_eq!(txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
2998+
txn.remove(0)
2999+
};
29923000

29933001
mine_transaction(&nodes[1], &timeout_tx);
29943002
check_added_monitors!(nodes[1], 1);
@@ -7312,17 +7320,21 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
73127320
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
73137321
connect_blocks(&nodes[1], 49); // Confirm blocks until the HTLC expires (note CLTV was explicitly 50 above)
73147322

7315-
let revoked_htlc_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
7316-
assert_eq!(revoked_htlc_txn.len(), 2);
7323+
let revoked_htlc_txn = {
7324+
let txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
7325+
assert_eq!(txn.len(), 2);
73177326

7318-
assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
7319-
assert_eq!(revoked_htlc_txn[0].input.len(), 1);
7320-
check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]);
7327+
assert_eq!(txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
7328+
assert_eq!(txn[0].input.len(), 1);
7329+
check_spends!(txn[0], revoked_local_txn[0]);
7330+
7331+
assert_eq!(txn[1].input.len(), 1);
7332+
assert_eq!(txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
7333+
assert_eq!(txn[1].output.len(), 1);
7334+
check_spends!(txn[1], revoked_local_txn[0]);
73217335

7322-
assert_eq!(revoked_htlc_txn[1].input.len(), 1);
7323-
assert_eq!(revoked_htlc_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
7324-
assert_eq!(revoked_htlc_txn[1].output.len(), 1);
7325-
check_spends!(revoked_htlc_txn[1], revoked_local_txn[0]);
7336+
txn
7337+
};
73267338

73277339
// Broadcast set of revoked txn on A
73287340
let hash_128 = connect_blocks(&nodes[0], 40);
@@ -8494,11 +8506,11 @@ fn test_concurrent_monitor_claim() {
84948506
watchtower_alice.chain_monitor.block_connected(&block, CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
84958507

84968508
// Watchtower Alice should have broadcast a commitment/HTLC-timeout
8497-
{
8498-
let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8509+
let alice_state = {
8510+
let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcast();
84998511
assert_eq!(txn.len(), 2);
8500-
txn.clear();
8501-
}
8512+
txn.remove(0)
8513+
};
85028514

85038515
// Copy ChainMonitor to simulate watchtower Bob and make it receive a commitment update first.
85048516
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
@@ -8549,19 +8561,21 @@ fn test_concurrent_monitor_claim() {
85498561
// Watchtower Bob should have broadcast a commitment/HTLC-timeout
85508562
let bob_state_y;
85518563
{
8552-
let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8564+
let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcast();
85538565
assert_eq!(txn.len(), 2);
8554-
bob_state_y = txn[0].clone();
8555-
txn.clear();
8566+
bob_state_y = txn.remove(0);
85568567
};
85578568

85588569
// We confirm Bob's state Y on Alice, she should broadcast a HTLC-timeout
85598570
let header = BlockHeader { version: 0x20000000, prev_blockhash: BlockHash::all_zeros(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 };
85608571
watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![bob_state_y.clone()] }, CHAN_CONFIRM_DEPTH + 2 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
85618572
{
8562-
let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8563-
assert_eq!(htlc_txn.len(), 1);
8573+
let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcast();
8574+
assert_eq!(htlc_txn.len(), 2);
85648575
check_spends!(htlc_txn[0], bob_state_y);
8576+
// Alice doesn't clean up the old HTLC claim since it hasn't seen a conflicting spend for
8577+
// it. However, she should, because it now has an invalid parent.
8578+
check_spends!(htlc_txn[1], alice_state);
85658579
}
85668580
}
85678581

0 commit comments

Comments
 (0)