Skip to content

Commit c5ee360

Browse files
author
Antoine Riard
committed
Add block_disconnecting tests to cancel HTLC failure updates
Add test_sweep_outbound_htlc_failure_update
1 parent 273f2fc commit c5ee360

File tree

2 files changed

+146
-2
lines changed

2 files changed

+146
-2
lines changed

src/ln/functional_test_utils.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use util::logger::Logger;
1515
use util::config::UserConfig;
1616

1717
use bitcoin::util::hash::BitcoinHash;
18-
use bitcoin::blockdata::block::BlockHeader;
18+
use bitcoin::blockdata::block::{BlockHeader, Block};
1919
use bitcoin::blockdata::transaction::{Transaction, TxOut};
2020
use bitcoin::network::constants::Network;
2121

@@ -47,13 +47,28 @@ pub fn confirm_transaction(chain: &chaininterface::ChainWatchInterfaceUtil, tx:
4747
}
4848
}
4949

50-
pub fn connect_blocks(chain: &chaininterface::ChainWatchInterfaceUtil, depth: u32, height: u32, parent: bool, prev_blockhash: Sha256d) {
50+
pub fn connect_blocks(chain: &chaininterface::ChainWatchInterfaceUtil, depth: u32, height: u32, parent: bool, prev_blockhash: Sha256d) -> Sha256d {
5151
let mut header = BlockHeader { version: 0x2000000, prev_blockhash: if parent { prev_blockhash } else { Default::default() }, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5252
chain.block_connected_checked(&header, height + 1, &Vec::new(), &Vec::new());
5353
for i in 2..depth + 1 {
5454
header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5555
chain.block_connected_checked(&header, height + i, &Vec::new(), &Vec::new());
5656
}
57+
header.bitcoin_hash()
58+
}
59+
60+
pub fn disconnect_blocks(chain: &chaininterface::ChainWatchInterfaceUtil, depth: u32, height: u32, parent: bool, prev_blockhash: Sha256d) {
61+
let mut header = BlockHeader { version: 0x2000000, prev_blockhash: if parent { prev_blockhash } else { Default::default() }, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
62+
let mut blocks = Vec::new();
63+
for _ in 0..depth {
64+
blocks.push(Block { header, txdata: Vec::new() });
65+
header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
66+
}
67+
let mut height = height;
68+
for block in blocks.pop() {
69+
chain.block_disconnected(&block.header, height);
70+
height -= 1;
71+
}
5772
}
5873

5974
pub struct Node {

src/ln/functional_tests.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5653,3 +5653,132 @@ fn test_no_failure_dust_htlc_local_commitment() {
56535653
claim_payment(&nodes[0], &vec!(&nodes[1])[..], preimage_1);
56545654
claim_payment(&nodes[1], &vec!(&nodes[0])[..], preimage_2);
56555655
}
5656+
5657+
fn do_test_sweep_outbound_htlc_failure_update(revoked: bool, local: bool) {
5658+
// Outbound HTLC-failure updates must be cancelled if we get a reorg before we reach HTLC_FAIL_ANTI_REORG_DELAY.
5659+
// Broadcast of revoked remote commitment tx, trigger failure-update of dust/non-dust HTLCs
5660+
// Broadcast of remote commitment tx, trigger failure-update of dust-HTLCs
5661+
// Broadcast of timeout tx on remote commitment tx, trigger failure-udate of non-dust HTLCs
5662+
// Broadcast of local commitment tx, trigger failure-update of dust-HTLCs
5663+
// Broadcast of HTLC-timeout tx on local commitment tx, trigger failure-update of non-dust HTLCs
5664+
5665+
let nodes = create_network(3);
5666+
let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
5667+
5668+
let bs_dust_limit = nodes[1].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().our_dust_limit_satoshis;
5669+
5670+
let (payment_preimage_1, dust_hash) = route_payment(&nodes[0], &[&nodes[1]], bs_dust_limit*1000);
5671+
let (payment_preimage_2, non_dust_hash) = route_payment(&nodes[0], &[&nodes[1]], 1000000);
5672+
5673+
let as_commitment_tx = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().last_local_commitment_txn.clone();
5674+
let bs_commitment_tx = nodes[1].node.channel_state.lock().unwrap().by_id.get(&chan.2).unwrap().last_local_commitment_txn.clone();
5675+
5676+
// We revoked bs_commitment_tx
5677+
if revoked {
5678+
let (payment_preimage_3, _) = route_payment(&nodes[0], &[&nodes[1]], 1000000);
5679+
claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_3);
5680+
}
5681+
5682+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5683+
let mut timeout_tx = Vec::new();
5684+
if local {
5685+
// We fail dust-HTLC 1 by broadcast of local commitment tx
5686+
nodes[0].chain_monitor.block_connected_checked(&header, 1, &[&as_commitment_tx[0]], &[1; 1]);
5687+
let events = nodes[0].node.get_and_clear_pending_msg_events();
5688+
assert_eq!(events.len(), 1);
5689+
match events[0] {
5690+
MessageSendEvent::BroadcastChannelUpdate { .. } => {},
5691+
_ => panic!("Unexpected event"),
5692+
}
5693+
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
5694+
timeout_tx.push(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[0].clone());
5695+
let parent_hash = connect_blocks(&nodes[0].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY - 1, 2, true, header.bitcoin_hash());
5696+
let events = nodes[0].node.get_and_clear_pending_events();
5697+
assert_eq!(events.len(), 1);
5698+
match events[0] {
5699+
Event::PaymentFailed { payment_hash, .. } => {
5700+
assert_eq!(payment_hash, dust_hash);
5701+
},
5702+
_ => panic!("Unexpected event"),
5703+
}
5704+
assert_eq!(timeout_tx[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
5705+
// We fail non-dust-HTLC 2 by broadcast of local HTLC-timeout tx on local commitment tx
5706+
let header_2 = BlockHeader { version: 0x20000000, prev_blockhash: parent_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5707+
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
5708+
nodes[0].chain_monitor.block_connected_checked(&header_2, 7, &[&timeout_tx[0]], &[1; 1]);
5709+
let header_3 = BlockHeader { version: 0x20000000, prev_blockhash: header_2.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5710+
connect_blocks(&nodes[0].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY - 1, 8, true, header_3.bitcoin_hash());
5711+
let events = nodes[0].node.get_and_clear_pending_events();
5712+
assert_eq!(events.len(), 1);
5713+
match events[0] {
5714+
Event::PaymentFailed { payment_hash, .. } => {
5715+
assert_eq!(payment_hash, non_dust_hash);
5716+
},
5717+
_ => panic!("Unexpected event"),
5718+
}
5719+
} else {
5720+
// We fail dust-HTLC 1 by broadcast of remote commitment tx. If revoked, fail also non-dust HTLC
5721+
nodes[0].chain_monitor.block_connected_checked(&header, 1, &[&bs_commitment_tx[0]], &[1; 1]);
5722+
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
5723+
let events = nodes[0].node.get_and_clear_pending_msg_events();
5724+
assert_eq!(events.len(), 1);
5725+
match events[0] {
5726+
MessageSendEvent::BroadcastChannelUpdate { .. } => {},
5727+
_ => panic!("Unexpected event"),
5728+
}
5729+
timeout_tx.push(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[0].clone());
5730+
let parent_hash = connect_blocks(&nodes[0].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY - 1, 2, true, header.bitcoin_hash());
5731+
let header_2 = BlockHeader { version: 0x20000000, prev_blockhash: parent_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5732+
if !revoked {
5733+
let events = nodes[0].node.get_and_clear_pending_events();
5734+
assert_eq!(events.len(), 1);
5735+
match events[0] {
5736+
Event::PaymentFailed { payment_hash, .. } => {
5737+
assert_eq!(payment_hash, dust_hash);
5738+
},
5739+
_ => panic!("Unexpected event"),
5740+
}
5741+
assert_eq!(timeout_tx[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
5742+
// We fail non-dust-HTLC 2 by broadcast of local timeout tx on remote commitment tx
5743+
nodes[0].chain_monitor.block_connected_checked(&header_2, 7, &[&timeout_tx[0]], &[1; 1]);
5744+
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
5745+
let header_3 = BlockHeader { version: 0x20000000, prev_blockhash: header_2.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5746+
connect_blocks(&nodes[0].chain_monitor, HTLC_FAIL_ANTI_REORG_DELAY - 1, 8, true, header_3.bitcoin_hash());
5747+
let events = nodes[0].node.get_and_clear_pending_events();
5748+
assert_eq!(events.len(), 1);
5749+
match events[0] {
5750+
Event::PaymentFailed { payment_hash, .. } => {
5751+
assert_eq!(payment_hash, non_dust_hash);
5752+
},
5753+
_ => panic!("Unexpected event"),
5754+
}
5755+
} else {
5756+
// If revoked, both dust & non-dust HTLCs should have been failed after HTLC_FAIL_ANTI_REORG_DELAY confs of revoked
5757+
// commitment tx
5758+
let events = nodes[0].node.get_and_clear_pending_events();
5759+
assert_eq!(events.len(), 2);
5760+
let first;
5761+
match events[0] {
5762+
Event::PaymentFailed { payment_hash, .. } => {
5763+
if payment_hash == dust_hash { first = true; }
5764+
else { first = false; }
5765+
},
5766+
_ => panic!("Unexpected event"),
5767+
}
5768+
match events[1] {
5769+
Event::PaymentFailed { payment_hash, .. } => {
5770+
if first { assert_eq!(payment_hash, non_dust_hash); }
5771+
else { assert_eq!(payment_hash, dust_hash); }
5772+
},
5773+
_ => panic!("Unexpected event"),
5774+
}
5775+
}
5776+
}
5777+
}
5778+
5779+
#[test]
5780+
fn test_sweep_outbound_htlc_failure_update() {
5781+
do_test_sweep_outbound_htlc_failure_update(false, true);
5782+
do_test_sweep_outbound_htlc_failure_update(false, false);
5783+
do_test_sweep_outbound_htlc_failure_update(true, false);
5784+
}

0 commit comments

Comments
 (0)