diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index cb8d64ecf15..4c47382958d 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -4672,6 +4672,122 @@ macro_rules! check_spendable_outputs { } } +#[test] +fn test_peer_storage_on_revoked_txn() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let (persister, chain_monitor); + let (persister_fund_recoverer, chain_monitor_fund_recoverer); + + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes_0_deserialized; + let nodes_0_deserialized_fund_recoverer; + let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let nodes_0_serialized = nodes[0].node.encode(); + + let (_a, _b, channel_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 1, 0); + + send_payment(&nodes[1], &vec!(&nodes[0])[..], 10000); + send_payment(&nodes[1], &vec!(&nodes[0])[..], 10000); + + let revoked_local_txn = get_local_commitment_txn!(nodes[1], channel_id); + assert_eq!(revoked_local_txn[0].input.len(), 1); + assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, funding_tx.txid()); + + send_payment(&nodes[1], &vec!(&nodes[0])[..], 10000); + + nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id()); + nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id()); + + // Lets drop the monitor and clear the chain_monitor as well. + nodes[0].chain_source.remove_watched_txn_and_outputs( + OutPoint { txid: funding_tx.txid(), index: 0 }, + funding_tx.output[0].script_pubkey.clone() + ); + + reload_node!(nodes[0], test_default_channel_config(), &nodes_0_serialized, &[], persister, chain_monitor, nodes_0_deserialized); + + // Reconnect peers to see if we send YourPeerStorage + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { + features: nodes[0].node.init_features(), networks: None, remote_network_address: None + }, false).unwrap(); + let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); + assert_eq!(reestablish_2.len(), 1); + + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { + features: nodes[1].node.init_features(), networks: None, remote_network_address: None + }, true).unwrap(); + let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); + assert_eq!(reestablish_1.len(), 0); + + nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id()); + nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id()); + + let chanstub = get_stub!(nodes[0], channel_id).encode(); + + // Lets drop the monitor and clear the chain_monitor as well. + nodes[0].chain_source.remove_watched_txn_and_outputs( + OutPoint { txid: funding_tx.txid(), index: 0 }, + funding_tx.output[0].script_pubkey.clone() + ); + + reload_node_with_stubs!(nodes[0], &nodes_0_serialized, &[], &[&chanstub], persister_fund_recoverer, chain_monitor_fund_recoverer, nodes_0_deserialized_fund_recoverer); + + let fundrecoverer: FundRecoverer<&test_utils::TestKeysInterface, &TestLogger, &test_utils::TestChainMonitor> + = FundRecoverer::new(&chain_monitor_fund_recoverer, node_cfgs[0].logger, test_default_channel_config(), ChainParameters{network: Network::Testnet, + best_block: BestBlock::from_network(Network::Testnet)}); + + fundrecoverer.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { + features: nodes[0].node.init_features(), networks: None, remote_network_address: None + }, true).unwrap(); + let mut closing_msg_events = fundrecoverer.get_and_clear_pending_msg_events(); + assert_eq!(closing_msg_events.len(), 1); + let bogus_chan_reestablish = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut closing_msg_events); + + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { + features: nodes[0].node.init_features(), networks: None, remote_network_address: None + }, true).unwrap(); + let reestablish_1 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); + assert_eq!(reestablish_1.len(), 1); + + match bogus_chan_reestablish { + MessageSendEvent::SendChannelReestablish {ref node_id, ref msg} => { + assert_eq!(nodes[1].node.get_our_node_id(), *node_id); + nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), msg); + }, + _ => panic!("Unexpected event"), + } + + fundrecoverer.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &reestablish_1[0]); + + let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![revoked_local_txn[0].clone()]); + connect_block(&nodes[0], &block); + connect_block(&nodes[1], &block); + check_closed_broadcast!(nodes[1], true); + + let events_2 = nodes[1].node.get_and_clear_pending_events(); + assert_eq!(events_2.len(), 1); + match events_2[0] { + Event::ChannelClosed {..} => {}, // If we actually processed we'd receive the payment + _ => panic!("Unexpected event"), + } + check_added_monitors!(nodes[1], 1); + + let panelty = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); + assert_eq!(panelty.len(), 1); + assert_eq!(panelty[0].input.len(), 1); + + let block = create_dummy_block(nodes[1].best_block_hash(), 42, vec![panelty[0].clone()]); + connect_block(&nodes[1], &block); + connect_block(&nodes[0], &block); + + connect_blocks(&nodes[0], CHAN_CONFIRM_DEPTH); + let spend_txn = check_spendable_outputs!(nodes[0], node_cfgs[0].keys_manager); + assert_eq!(spend_txn.len(), 1); + assert_eq!(spend_txn[0].input.len(), 1); + check_spends!(spend_txn[0], panelty[0]); +} + #[test] fn test_claim_sizeable_push_msat() { // Incidentally test SpendableOutput event generation due to detection of to_local output on commitment tx