Skip to content

Commit 2035aaa

Browse files
Aditya SharmaAditya Sharma
Aditya Sharma
authored and
Aditya Sharma
committed
Add test for sweeping funds from a revoked transaction
Introduce test_peer_storage_on_revoked_txn to validate fund recovery in the event of a revoked transaction. This test establishes a channel between two nodes, simulates one node attempting to cheat by broadcasting a revoked state on-chain, and demonstrates recovering funds using PeerStorage by generating and broadcasting a penalty transaction. - Add test_peer_storage_on_revoked_txn to test the recovery of funds via a penalty transaction created using data from PeerStorage.
1 parent 5075faa commit 2035aaa

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed

lightning/src/ln/functional_tests.rs

+195
Original file line numberDiff line numberDiff line change
@@ -4703,6 +4703,201 @@ macro_rules! check_spendable_outputs {
47034703
}
47044704
}
47054705

4706+
#[test]
4707+
fn test_peer_storage_on_revoked_txn() {
4708+
let chanmon_cfgs = create_chanmon_cfgs(2);
4709+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
4710+
let (persister, chain_monitor);
4711+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
4712+
let nodes_0_deserialized;
4713+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
4714+
let nodes_0_serialized = nodes[0].node.encode();
4715+
4716+
let (_a, _b, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 1, 0);
4717+
4718+
let msg_events_a = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_msg_events();
4719+
for msg in msg_events_a {
4720+
if let MessageSendEvent::SendPeerStorageMessage { node_id: _, ref msg } = msg {
4721+
nodes[1].node.handle_peer_storage(nodes[0].node.get_our_node_id(), msg);
4722+
} else {
4723+
panic!("Unexpected event");
4724+
}
4725+
}
4726+
4727+
let msg_events_b = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_msg_events();
4728+
for msg in msg_events_b {
4729+
if let MessageSendEvent::SendPeerStorageMessage { node_id: _, ref msg } = msg {
4730+
nodes[0].node.handle_peer_storage(nodes[1].node.get_our_node_id(), msg);
4731+
} else {
4732+
panic!("Unexpected event");
4733+
}
4734+
}
4735+
4736+
send_payment(&nodes[1], &vec!(&nodes[0])[..], 10000);
4737+
send_payment(&nodes[1], &vec!(&nodes[0])[..], 10000);
4738+
4739+
let revoked_local_txn = get_local_commitment_txn!(nodes[1], channel_id);
4740+
assert_eq!(revoked_local_txn[0].input.len(), 1);
4741+
assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, funding_tx.compute_txid());
4742+
4743+
send_payment(&nodes[1], &vec!(&nodes[0])[..], 10000);
4744+
4745+
connect_blocks(&nodes[1], 2);
4746+
connect_blocks(&nodes[0], 2);
4747+
4748+
let msg_events_aa = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_msg_events();
4749+
for msg in msg_events_aa {
4750+
if let MessageSendEvent::SendPeerStorageMessage { node_id: _, ref msg } = msg {
4751+
nodes[0].node.handle_peer_storage(nodes[1].node.get_our_node_id(), msg);
4752+
} else {
4753+
panic!("Unexpected event");
4754+
}
4755+
}
4756+
let msg_events_bb = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_msg_events();
4757+
for msg in msg_events_bb {
4758+
if let MessageSendEvent::SendPeerStorageMessage { node_id: _, ref msg } = msg {
4759+
nodes[1].node.handle_peer_storage(nodes[0].node.get_our_node_id(), msg);
4760+
} else {
4761+
panic!("Unexpected event");
4762+
}
4763+
}
4764+
4765+
nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id());
4766+
nodes[1].node.peer_disconnected(nodes[0].node.get_our_node_id());
4767+
4768+
// Reconnect peers
4769+
nodes[0].node.peer_connected(nodes[1].node.get_our_node_id(), &msgs::Init {
4770+
features: nodes[1].node.init_features(), networks: None, remote_network_address: None
4771+
}, true).unwrap();
4772+
let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]);
4773+
assert_eq!(reestablish_1.len(), 1);
4774+
nodes[1].node.peer_connected(nodes[0].node.get_our_node_id(), &msgs::Init {
4775+
features: nodes[0].node.init_features(), networks: None, remote_network_address: None
4776+
}, false).unwrap();
4777+
let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]);
4778+
assert_eq!(reestablish_2.len(), 1);
4779+
4780+
nodes[0].node.handle_channel_reestablish(nodes[1].node.get_our_node_id(), &reestablish_2[0]);
4781+
handle_chan_reestablish_msgs!(nodes[0], nodes[1]);
4782+
nodes[1].node.handle_channel_reestablish(nodes[0].node.get_our_node_id(), &reestablish_1[0]);
4783+
handle_chan_reestablish_msgs!(nodes[1], nodes[0]);
4784+
4785+
nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id());
4786+
nodes[1].node.peer_disconnected(nodes[0].node.get_our_node_id());
4787+
4788+
// Lets drop the monitor and clear the chain_monitor as well.
4789+
nodes[0].chain_source.clear_watched_txn_and_outputs();
4790+
reload_node!(nodes[0], test_default_channel_config(), &nodes_0_serialized, &[], persister, chain_monitor, nodes_0_deserialized);
4791+
let persister: &dyn Persist<TestChannelSigner> = &chanmon_cfgs[0].persister;
4792+
4793+
let fundrecoverer
4794+
= FundRecoverer::new(node_cfgs[0].keys_manager, node_cfgs[0].logger,test_default_channel_config(), ChainParameters {network: Network::Testnet,
4795+
best_block: BestBlock::from_network(Network::Testnet)}, node_cfgs[0].keys_manager, node_cfgs[0].keys_manager, Some(&chanmon_cfgs[0].chain_source),
4796+
persister, node_cfgs[0].fee_estimator, node_cfgs[0].tx_broadcaster, Vec::new());
4797+
4798+
fundrecoverer.peer_connected(nodes[1].node.get_our_node_id(), &msgs::Init {
4799+
features: nodes[0].node.init_features(), networks: None, remote_network_address: None
4800+
}, true).unwrap();
4801+
4802+
nodes[1].node.peer_connected(nodes[0].node.get_our_node_id(), &msgs::Init {
4803+
features: nodes[0].node.init_features(), networks: None, remote_network_address: None
4804+
}, true).unwrap();
4805+
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
4806+
// 0th - SendYourPeerStorageMessage
4807+
// 2nd - SendChannelReestablish
4808+
assert_eq!(msg_events.len(), 2);
4809+
for msg in msg_events {
4810+
if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg {
4811+
fundrecoverer.handle_channel_reestablish(nodes[1].node.get_our_node_id(), msg);
4812+
assert_eq!(*node_id, nodes[0].node.get_our_node_id());
4813+
} else if let MessageSendEvent::SendYourPeerStorageMessage { ref node_id, ref msg } = msg {
4814+
fundrecoverer.handle_your_peer_storage(nodes[1].node.get_our_node_id(), msg);
4815+
assert_eq!(*node_id, nodes[0].node.get_our_node_id());
4816+
} else {
4817+
panic!("Unexpected event")
4818+
}
4819+
}
4820+
4821+
let recovery_event = fundrecoverer.get_and_clear_recovery_pending_events();
4822+
assert_eq!(recovery_event.len(), 1);
4823+
match recovery_event[0] {
4824+
RecoveryEvent::RescanBlock{..} => {},
4825+
};
4826+
4827+
let bogus_chan_reestablish = fundrecoverer.get_and_clear_pending_msg_events();
4828+
4829+
// We receive two `channel_reestablish`(bogus) messages: the first from `handle_your_peer_storage` and the second from `handle_channel_reestablish`.
4830+
assert_eq!(bogus_chan_reestablish.len(), 2);
4831+
4832+
match bogus_chan_reestablish[0] {
4833+
MessageSendEvent::SendChannelReestablish {ref node_id, ref msg} => {
4834+
assert_eq!(nodes[1].node.get_our_node_id(), *node_id);
4835+
nodes[1].node.handle_channel_reestablish(nodes[0].node.get_our_node_id(), msg);
4836+
},
4837+
_ => panic!("Unexpected event"),
4838+
}
4839+
4840+
let block = create_dummy_block(nodes[0].best_block_hash(), 42, vec![revoked_local_txn[0].clone()]);
4841+
connect_block(&nodes[1], &block);
4842+
// Since we are using fundrecoverer as Chain::watch.
4843+
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
4844+
let height = nodes[0].best_block_info().1 + 1;
4845+
4846+
nodes[0].blocks.lock().unwrap().push((block.clone(), height));
4847+
fundrecoverer.best_block_updated(&block.header, height);
4848+
fundrecoverer.transactions_confirmed(&block.header, &txdata, height);
4849+
4850+
check_closed_broadcast!(nodes[1], true);
4851+
4852+
let events_2 = nodes[1].node.get_and_clear_pending_events();
4853+
assert_eq!(events_2.len(), 1);
4854+
match events_2[0] {
4855+
Event::ChannelClosed {..} => {}, // If we actually processed we'd receive the payment
4856+
_ => panic!("Unexpected event"),
4857+
}
4858+
check_added_monitors!(nodes[1], 1);
4859+
4860+
let panelty = node_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
4861+
assert_eq!(panelty.len(), 1);
4862+
assert_eq!(panelty[0].input.len(), 1);
4863+
4864+
let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![panelty[0].clone()]);
4865+
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
4866+
connect_block(&nodes[1], &block);
4867+
4868+
nodes[0].blocks.lock().unwrap().push((block.clone(), height + 1));
4869+
fundrecoverer.best_block_updated(&block.header, height + 1);
4870+
fundrecoverer.transactions_confirmed(&block.header, &txdata, height + 1);
4871+
4872+
let mut dummy_block = create_dummy_block(nodes[1].best_block_hash(), height, Vec::new());
4873+
for i in 1..CHAN_CONFIRM_DEPTH {
4874+
let prev_blockhash = dummy_block.header.block_hash();
4875+
let dummy_txdata: Vec<_> = dummy_block.txdata.iter().enumerate().collect();
4876+
fundrecoverer.best_block_updated(&dummy_block.header, height + i + 1);
4877+
fundrecoverer.transactions_confirmed(&dummy_block.header, &dummy_txdata, height + i + 1);
4878+
dummy_block = create_dummy_block(prev_blockhash, height + i + 1, Vec::new());
4879+
}
4880+
4881+
// Lets drop the monitor and clear the chain_monitor as well.
4882+
nodes[0].chain_source.clear_watched_txn_and_outputs();
4883+
4884+
for event in fundrecoverer.get_and_clear_pending_events() {
4885+
match event {
4886+
Event::SpendableOutputs { mut outputs, channel_id: _ } => {
4887+
for outp in outputs.drain(..) {
4888+
match outp {
4889+
SpendableOutputDescriptor::StaticOutput{output, ..} => {
4890+
assert_eq!(output.value.to_sat(), panelty[0].output[0].value.to_sat());
4891+
},
4892+
_ => panic!("Unexpected event"),
4893+
}
4894+
}
4895+
},
4896+
_ => panic!("Unexpected event"),
4897+
};
4898+
}
4899+
}
4900+
47064901
#[test]
47074902
fn test_claim_sizeable_push_msat() {
47084903
// Incidentally test SpendableOutput event generation due to detection of to_local output on commitment tx

0 commit comments

Comments
 (0)