Skip to content

Commit b63ab7d

Browse files
committed
Do not test any block-contents-rescan cases
In anticipation for removing support for users calling block_connected multiple times for the same block to include all relevant transactions in the next PR, this commit stops testing such cases. Specifically, users who filter blocks for relevant transactions before calling block_connected will need to filter by including any transactions which spend a previously-matched transaction in the same block (and we now do so in our own filtering logic, which is also used in our testing).
1 parent 6da6d60 commit b63ab7d

File tree

2 files changed

+52
-34
lines changed

2 files changed

+52
-34
lines changed

lightning/src/chain/chaininterface.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,19 @@ impl ChainWatchInterface for ChainWatchInterfaceUtil {
377377

378378
fn filter_block(&self, block: &Block) -> Vec<usize> {
379379
let mut matched_index = Vec::new();
380+
let mut match_set = HashSet::new();
380381
{
381382
let watched = self.watched.lock().unwrap();
382383
for (index, transaction) in block.txdata.iter().enumerate() {
383-
if self.does_match_tx_unguarded(transaction, &watched) {
384+
let mut matched = self.does_match_tx_unguarded(transaction, &watched);
385+
for input in transaction.input.iter() {
386+
if matched || match_set.contains(&input.previous_output.txid) {
387+
matched = true;
388+
break;
389+
}
390+
}
391+
if matched {
392+
match_set.insert(transaction.txid());
384393
matched_index.push(index);
385394
}
386395
}

lightning/src/ln/functional_tests.rs

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5037,33 +5037,34 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() {
50375037
check_added_monitors!(nodes[1], 1);
50385038

50395039
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
5040-
assert_eq!(node_txn.len(), 4); // ChannelMonitor: justice tx on revoked commitment, justice tx on revoked HTLC-timeout, adjusted justice tx, ChannelManager: local commitment tx
5040+
assert_eq!(node_txn.len(), 3); // ChannelMonitor: bogus justics tx, justice tx on revoked outputs, ChannelManager: local commitment tx
50415041
// The first transaction generated is bogus - it spends both outputs of revoked_local_txn[0]
50425042
// including the one already spent by revoked_htlc_txn[0]. That's OK, we'll spend with valid
50435043
// transactions next...
5044-
assert_eq!(node_txn[0].input.len(), 2);
5045-
check_spends!(node_txn[0], revoked_local_txn[0]);
5044+
assert_eq!(node_txn[0].input.len(), 3);
5045+
check_spends!(node_txn[0], revoked_local_txn[0], revoked_htlc_txn[0]);
50465046

5047-
check_spends!(node_txn[1], chan_1.3);
5047+
assert_eq!(node_txn[1].input.len(), 2);
5048+
check_spends!(node_txn[1], revoked_local_txn[0], revoked_htlc_txn[0]);
5049+
if node_txn[1].input[1].previous_output.txid == revoked_htlc_txn[0].txid() {
5050+
assert_ne!(node_txn[1].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
5051+
} else {
5052+
assert_eq!(node_txn[1].input[0].previous_output.txid, revoked_htlc_txn[0].txid());
5053+
assert_ne!(node_txn[1].input[1].previous_output, revoked_htlc_txn[0].input[0].previous_output);
5054+
}
50485055

50495056
assert_eq!(node_txn[2].input.len(), 1);
5050-
check_spends!(node_txn[2], revoked_htlc_txn[0]);
5051-
assert_eq!(node_txn[3].input.len(), 1);
5052-
check_spends!(node_txn[3], revoked_local_txn[0]);
5057+
check_spends!(node_txn[2], chan_1.3);
50535058

50545059
let header_1 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5055-
nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[2].clone(), node_txn[3].clone()] }, 1);
5060+
nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[1].clone()] }, 1);
50565061
connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.block_hash());
50575062

5058-
// Note that nodes[1]'s tx_broadcaster is still locked, so if we get here the channelmonitor
5059-
// didn't try to generate any new transactions.
5060-
5061-
// Check B's ChannelMonitor was able to generate the right spendable output descriptor which
5062-
// allows the user to spend the newly-confirmed outputs.
5063+
// Check B's ChannelMonitor was able to generate the right spendable output descriptor
50635064
let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000);
5064-
assert_eq!(spend_txn.len(), 2);
5065-
check_spends!(spend_txn[0], node_txn[2]);
5066-
check_spends!(spend_txn[1], node_txn[3]);
5065+
assert_eq!(spend_txn.len(), 1);
5066+
assert_eq!(spend_txn[0].input.len(), 1);
5067+
check_spends!(spend_txn[0], node_txn[1]);
50675068
}
50685069

50695070
#[test]
@@ -5110,33 +5111,38 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() {
51105111
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
51115112
assert_eq!(node_txn.len(), 3); // ChannelMonitor: justice tx on revoked commitment, justice tx on revoked HTLC-success, ChannelManager: local commitment tx
51125113

5113-
// The first transaction generated is just in case of a reorg - it double-spends
5114-
// revoked_htlc_txn[0], spending the HTLC output on revoked_local_txn[0] directly.
5115-
assert_eq!(node_txn[0].input.len(), 1);
5116-
check_spends!(node_txn[0], revoked_local_txn[0]);
5117-
assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
5114+
// The first transaction generated is bogus - it spends both outputs of revoked_local_txn[0]
5115+
// including the one already spent by revoked_htlc_txn[0]. That's OK, we'll spend with valid
5116+
// transactions next...
5117+
assert_eq!(node_txn[0].input.len(), 2);
5118+
check_spends!(node_txn[0], revoked_local_txn[0], revoked_htlc_txn[0]);
5119+
if node_txn[0].input[1].previous_output.txid == revoked_htlc_txn[0].txid() {
5120+
assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
5121+
} else {
5122+
assert_eq!(node_txn[0].input[0].previous_output.txid, revoked_htlc_txn[0].txid());
5123+
assert_eq!(node_txn[0].input[1].previous_output, revoked_htlc_txn[0].input[0].previous_output);
5124+
}
51185125

5119-
assert_eq!(node_txn[2].input.len(), 1);
5120-
check_spends!(node_txn[2], revoked_htlc_txn[0]);
5126+
assert_eq!(node_txn[1].input.len(), 1);
5127+
check_spends!(node_txn[1], revoked_htlc_txn[0]);
51215128

5122-
check_spends!(node_txn[1], chan_1.3);
5129+
check_spends!(node_txn[2], chan_1.3);
51235130

51245131
let header_1 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5125-
nodes[0].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[2].clone()] }, 1);
5132+
nodes[0].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[1].clone()] }, 1);
51265133
connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.block_hash());
51275134

51285135
// Note that nodes[0]'s tx_broadcaster is still locked, so if we get here the channelmonitor
51295136
// didn't try to generate any new transactions.
51305137

51315138
// Check A's ChannelMonitor was able to generate the right spendable output descriptor
51325139
let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 100000);
5133-
assert_eq!(spend_txn.len(), 4); // Duplicated SpendableOutput due to block rescan after revoked htlc output tracking
5140+
assert_eq!(spend_txn.len(), 3); // Duplicated SpendableOutput due to block rescan after revoked htlc output tracking
51345141
assert_eq!(spend_txn[0], spend_txn[1]);
5135-
assert_eq!(spend_txn[0], spend_txn[2]);
51365142
assert_eq!(spend_txn[0].input.len(), 1);
51375143
check_spends!(spend_txn[0], revoked_local_txn[0]); // spending to_remote output from revoked local tx
51385144
assert_ne!(spend_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output);
5139-
check_spends!(spend_txn[3], node_txn[2]); // spending justice tx output on the htlc success tx
5145+
check_spends!(spend_txn[2], node_txn[1]); // spending justice tx output on the htlc success tx
51405146
}
51415147

51425148
#[test]
@@ -7798,11 +7804,11 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
77987804
}
77997805

78007806
// Broadcast set of revoked txn on A
7801-
let header_128 = connect_blocks(&nodes[0].block_notifier, 128, 0, true, header.block_hash());
7807+
let header_128 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
7808+
nodes[0].block_notifier.block_connected(&Block { header: header_128, txdata: vec![revoked_local_txn[0].clone()] }, 128);
78027809
expect_pending_htlcs_forwardable_ignore!(nodes[0]);
7803-
7804-
let header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_128, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
7805-
nodes[0].block_notifier.block_connected(&Block { header: header_129, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()] }, 129);
7810+
let header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_128.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
7811+
nodes[0].block_notifier.block_connected(&Block { header: header_129, txdata: vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()] }, 129);
78067812
let first;
78077813
let feerate_1;
78087814
let penalty_txn;
@@ -7838,6 +7844,7 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
78387844
assert_eq!(node_txn[4].input.len(), 2);
78397845
assert_eq!(node_txn[4].output.len(), 1);
78407846
check_spends!(node_txn[4], revoked_htlc_txn[0], revoked_htlc_txn[1]);
7847+
78417848
first = node_txn[4].txid();
78427849
// Store both feerates for later comparison
78437850
let fee_1 = revoked_htlc_txn[0].output[0].value + revoked_htlc_txn[1].output[0].value - node_txn[4].output[0].value;
@@ -7849,6 +7856,8 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
78497856
// Connect one more block to see if bumped penalty are issued for HTLC txn
78507857
let header_130 = BlockHeader { version: 0x20000000, prev_blockhash: header_129.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
78517858
nodes[0].block_notifier.block_connected(&Block { header: header_130, txdata: penalty_txn }, 130);
7859+
let header_131 = BlockHeader { version: 0x20000000, prev_blockhash: header_130.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
7860+
nodes[0].block_notifier.block_connected(&Block { header: header_131, txdata: Vec::new() }, 131);
78527861
{
78537862
let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
78547863
assert_eq!(node_txn.len(), 2); // 2 bumped penalty txn on revoked commitment tx
@@ -7867,7 +7876,7 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
78677876
};
78687877

78697878
// Few more blocks to confirm penalty txn
7870-
let header_135 = connect_blocks(&nodes[0].block_notifier, 5, 130, true, header_130.block_hash());
7879+
let header_135 = connect_blocks(&nodes[0].block_notifier, 4, 131, true, header_131.block_hash());
78717880
assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
78727881
let header_144 = connect_blocks(&nodes[0].block_notifier, 9, 135, true, header_135);
78737882
let node_txn = {

0 commit comments

Comments
 (0)