Support pending update_fail_htlcs in reconnect_nodes test util
[rust-lightning] / lightning / src / ln / functional_tests.rs
index 060097c5f4a30abe18139ebb9ab14800a38d50f3..f296cb3a7e7b0e9bdec20803eac57d83237a9a25 100644 (file)
@@ -12,8 +12,7 @@
 //! claim outputs on-chain.
 
 use chain;
-use chain::Listen;
-use chain::Watch;
+use chain::{Confirm, Listen, Watch};
 use chain::channelmonitor;
 use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
 use chain::transaction::OutPoint;
@@ -1879,11 +1878,12 @@ fn test_inbound_outbound_capacity_is_not_zero() {
        assert_eq!(channels0.len(), 1);
        assert_eq!(channels1.len(), 1);
 
-       assert_eq!(channels0[0].inbound_capacity_msat, 95000000);
-       assert_eq!(channels1[0].outbound_capacity_msat, 95000000);
+       let reserve = Channel::<EnforcingSigner>::get_holder_selected_channel_reserve_satoshis(100000);
+       assert_eq!(channels0[0].inbound_capacity_msat, 95000000 - reserve*1000);
+       assert_eq!(channels1[0].outbound_capacity_msat, 95000000 - reserve*1000);
 
-       assert_eq!(channels0[0].outbound_capacity_msat, 100000 * 1000 - 95000000);
-       assert_eq!(channels1[0].inbound_capacity_msat, 100000 * 1000 - 95000000);
+       assert_eq!(channels0[0].outbound_capacity_msat, 100000 * 1000 - 95000000 - reserve*1000);
+       assert_eq!(channels1[0].inbound_capacity_msat, 100000 * 1000 - 95000000 - reserve*1000);
 }
 
 fn commit_tx_fee_msat(feerate: u32, num_htlcs: u64) -> u64 {
@@ -3001,10 +3001,16 @@ fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) {
 
        connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
        {
-               // B will rebroadcast its own holder commitment transaction here...just because
+               // B may rebroadcast its own holder commitment transaction here, as a safeguard against
+               // some incredibly unlikely partial-eclipse-attack scenarios. That said, because the
+               // original commitment_tx[0] (also spending chan_2.3) has reached ANTI_REORG_DELAY B really
+               // shouldn't broadcast anything here, and in some connect style scenarios we do not.
                let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
-               assert_eq!(node_txn.len(), 1);
-               check_spends!(node_txn[0], chan_2.3);
+               if node_txn.len() == 1 {
+                       check_spends!(node_txn[0], chan_2.3);
+               } else {
+                       assert_eq!(node_txn.len(), 0);
+               }
        }
 
        expect_pending_htlcs_forwardable!(nodes[1]);
@@ -3531,7 +3537,7 @@ fn test_dup_events_on_peer_disconnect() {
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
 
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (1, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (1, 0), (0, 0), (0, 0), (0, 0), (false, false));
        assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
 }
 
@@ -3547,7 +3553,7 @@ fn test_simple_peer_disconnect() {
 
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
-       reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
        let payment_hash_2 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).1;
@@ -3556,7 +3562,7 @@ fn test_simple_peer_disconnect() {
 
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        let payment_preimage_3 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
        let payment_preimage_4 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
@@ -3569,7 +3575,7 @@ fn test_simple_peer_disconnect() {
        claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], true, payment_preimage_3);
        fail_payment_along_route(&nodes[0], &[&nodes[1], &nodes[2]], true, payment_hash_5);
 
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (1, 0), (1, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (1, 0), (1, 0), (false, false));
        {
                let events = nodes[0].node.get_and_clear_pending_events();
                assert_eq!(events.len(), 2);
@@ -3673,19 +3679,19 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8, simulate_broken
                }
                // Even if the funding_locked messages get exchanged, as long as nothing further was
                // received on either side, both sides will need to resend them.
-               reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 1), (0, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 1), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        } else if messages_delivered == 3 {
                // nodes[0] still wants its RAA + commitment_signed
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (-1, 0), (0, 0), (0, 0), (0, 0), (true, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (-1, 0), (0, 0), (0, 0), (0, 0), (0, 0), (true, false));
        } else if messages_delivered == 4 {
                // nodes[0] still wants its commitment_signed
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (-1, 0), (0, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (-1, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        } else if messages_delivered == 5 {
                // nodes[1] still wants its final RAA
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, true));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, true));
        } else if messages_delivered == 6 {
                // Everything was delivered...
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        }
 
        let events_1 = nodes[1].node.get_and_clear_pending_events();
@@ -3697,7 +3703,7 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8, simulate_broken
 
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        nodes[1].node.process_pending_htlc_forwards();
 
@@ -3772,7 +3778,7 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8, simulate_broken
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
        if messages_delivered < 2 {
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (1, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (1, 0), (0, 0), (0, 0), (0, 0), (false, false));
                if messages_delivered < 1 {
                        let events_4 = nodes[0].node.get_and_clear_pending_events();
                        assert_eq!(events_4.len(), 1);
@@ -3787,21 +3793,21 @@ fn do_test_drop_messages_peer_disconnect(messages_delivered: u8, simulate_broken
                }
        } else if messages_delivered == 2 {
                // nodes[0] still wants its RAA + commitment_signed
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, -1), (0, 0), (0, 0), (0, 0), (false, true));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, -1), (0, 0), (0, 0), (0, 0), (0, 0), (false, true));
        } else if messages_delivered == 3 {
                // nodes[0] still wants its commitment_signed
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, -1), (0, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, -1), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        } else if messages_delivered == 4 {
                // nodes[1] still wants its final RAA
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (true, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (true, false));
        } else if messages_delivered == 5 {
                // Everything was delivered...
-               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+               reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        }
 
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        // Channel should still work fine...
        let net_graph_msg_handler = &nodes[0].net_graph_msg_handler;
@@ -3853,7 +3859,7 @@ fn test_funding_peer_disconnect() {
                _ => panic!("Unexpected event"),
        }
 
-       reconnect_nodes(&nodes[0], &nodes[1], (false, true), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
@@ -3876,7 +3882,7 @@ fn test_funding_peer_disconnect() {
                _ => panic!("Unexpected event"),
        };
 
-       reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (true, true), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        nodes[0].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &funding_locked);
        nodes[0].node.handle_announcement_signatures(&nodes[1].node.get_our_node_id(), &bs_announcement_sigs);
@@ -3954,7 +3960,7 @@ fn test_funding_peer_disconnect() {
        nodes[0].node = &nodes_0_deserialized;
        check_added_monitors!(nodes[0], 1);
 
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        // as_announcement should be re-generated exactly by broadcast_node_announcement.
        nodes[0].node.broadcast_node_announcement([0, 0, 0], [0; 32], Vec::new());
@@ -4690,7 +4696,7 @@ fn test_simple_manager_serialize_deserialize() {
        nodes[0].node = &nodes_0_deserialized;
        check_added_monitors!(nodes[0], 1);
 
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
 
        fail_payment(&nodes[0], &[&nodes[1]], our_payment_hash);
        claim_payment(&nodes[0], &[&nodes[1]], our_payment_preimage);
@@ -4804,8 +4810,8 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
        nodes[0].node = &nodes_0_deserialized;
 
        // nodes[1] and nodes[2] have no lost state with nodes[0]...
-       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
-       reconnect_nodes(&nodes[0], &nodes[2], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
+       reconnect_nodes(&nodes[0], &nodes[2], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
        //... and we can even still claim the payment!
        claim_payment(&nodes[2], &[&nodes[0], &nodes[1]], our_payment_preimage);
 
@@ -9279,3 +9285,86 @@ fn test_invalid_funding_tx() {
        } else { panic!(); }
        assert_eq!(nodes[1].node.list_channels().len(), 0);
 }
+
+fn do_test_tx_confirmed_skipping_blocks_immediate_broadcast(test_height_before_timelock: bool) {
+       // In the first version of the chain::Confirm interface, after a refactor was made to not
+       // broadcast CSV-locked transactions until their CSV lock is up, we wouldn't reliably broadcast
+       // transactions after a `transactions_confirmed` call. Specifically, if the chain, provided via
+       // `best_block_updated` is at height N, and a transaction output which we wish to spend at
+       // height N-1 (due to a CSV to height N-1) is provided at height N, we will not broadcast the
+       // spending transaction until height N+1 (or greater). This was due to the way
+       // `ChannelMonitor::transactions_confirmed` worked, only checking if we should broadcast a
+       // spending transaction at the height the input transaction was confirmed at, not whether we
+       // should broadcast a spending transaction at the current height.
+       // A second, similar, issue involved failing HTLCs backwards - because we only provided the
+       // height at which transactions were confirmed to `OnchainTx::update_claims_view`, it wasn't
+       // aware that the anti-reorg-delay had, in fact, already expired, waiting to fail-backwards
+       // until we learned about an additional block.
+       //
+       // As an additional check, if `test_height_before_timelock` is set, we instead test that we
+       // aren't broadcasting transactions too early (ie not broadcasting them at all).
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+       let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+       *nodes[0].connect_style.borrow_mut() = ConnectStyle::BestBlockFirstSkippingBlocks;
+
+       create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+       let (chan_announce, _, channel_id, _) = create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+       let (_, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000);
+       nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), false);
+       nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+
+       nodes[1].node.force_close_channel(&channel_id).unwrap();
+       check_closed_broadcast!(nodes[1], true);
+       check_added_monitors!(nodes[1], 1);
+       let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+       assert_eq!(node_txn.len(), 1);
+
+       let conf_height = nodes[1].best_block_info().1;
+       if !test_height_before_timelock {
+               connect_blocks(&nodes[1], 24 * 6);
+       }
+       nodes[1].chain_monitor.chain_monitor.transactions_confirmed(
+               &nodes[1].get_block_header(conf_height), &[(0, &node_txn[0])], conf_height);
+       if test_height_before_timelock {
+               // If we confirmed the close transaction, but timelocks have not yet expired, we should not
+               // generate any events or broadcast any transactions
+               assert!(nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
+               assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
+       } else {
+               // We should broadcast an HTLC transaction spending our funding transaction first
+               let spending_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+               assert_eq!(spending_txn.len(), 2);
+               assert_eq!(spending_txn[0], node_txn[0]);
+               check_spends!(spending_txn[1], node_txn[0]);
+               // We should also generate a SpendableOutputs event with the to_self output (as its
+               // timelock is up).
+               let descriptor_spend_txn = check_spendable_outputs!(nodes[1], node_cfgs[1].keys_manager);
+               assert_eq!(descriptor_spend_txn.len(), 1);
+
+               // If we also discover that the HTLC-Timeout transaction was confirmed some time ago, we
+               // should immediately fail-backwards the HTLC to the previous hop, without waiting for an
+               // additional block built on top of the current chain.
+               nodes[1].chain_monitor.chain_monitor.transactions_confirmed(
+                       &nodes[1].get_block_header(conf_height + 1), &[(0, &spending_txn[1])], conf_height + 1);
+               expect_pending_htlcs_forwardable!(nodes[1]);
+               check_added_monitors!(nodes[1], 1);
+
+               let updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+               assert!(updates.update_add_htlcs.is_empty());
+               assert!(updates.update_fulfill_htlcs.is_empty());
+               assert_eq!(updates.update_fail_htlcs.len(), 1);
+               assert!(updates.update_fail_malformed_htlcs.is_empty());
+               assert!(updates.update_fee.is_none());
+               nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
+               commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, true, true);
+               expect_payment_failed!(nodes[0], payment_hash, false);
+               expect_payment_failure_chan_update!(nodes[0], chan_announce.contents.short_channel_id, true);
+       }
+}
+#[test]
+fn test_tx_confirmed_skipping_blocks_immediate_broadcast() {
+       do_test_tx_confirmed_skipping_blocks_immediate_broadcast(false);
+       do_test_tx_confirmed_skipping_blocks_immediate_broadcast(true);
+}