Merge pull request #1766 from tee8z/event-node-received
[rust-lightning] / lightning / src / ln / functional_test_utils.rs
index 162564824bba15a8131a265d5428a90a97d7504e..cd3041be8d32dda0a13e49ce2b2a98df744632ca 100644 (file)
@@ -107,6 +107,14 @@ pub enum ConnectStyle {
        /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only
        /// make a single `best_block_updated` call.
        TransactionsFirstSkippingBlocks,
+       /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only
+       /// make a single `best_block_updated` call. Further, we call `transactions_confirmed` multiple
+       /// times to ensure it's idempotent.
+       TransactionsDuplicativelyFirstSkippingBlocks,
+       /// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only
+       /// make a single `best_block_updated` call. Further, we call `transactions_confirmed` multiple
+       /// times to ensure it's idempotent.
+       HighlyRedundantTransactionsFirstSkippingBlocks,
        /// The same as `TransactionsFirst` when connecting blocks. During disconnection only
        /// `transaction_unconfirmed` is called.
        TransactionsFirstReorgsOnlyTip,
@@ -121,14 +129,16 @@ impl ConnectStyle {
                        use core::hash::{BuildHasher, Hasher};
                        // Get a random value using the only std API to do so - the DefaultHasher
                        let rand_val = std::collections::hash_map::RandomState::new().build_hasher().finish();
-                       let res = match rand_val % 7 {
+                       let res = match rand_val % 9 {
                                0 => ConnectStyle::BestBlockFirst,
                                1 => ConnectStyle::BestBlockFirstSkippingBlocks,
                                2 => ConnectStyle::BestBlockFirstReorgsOnlyTip,
                                3 => ConnectStyle::TransactionsFirst,
                                4 => ConnectStyle::TransactionsFirstSkippingBlocks,
-                               5 => ConnectStyle::TransactionsFirstReorgsOnlyTip,
-                               6 => ConnectStyle::FullBlockViaListen,
+                               5 => ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks,
+                               6 => ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks,
+                               7 => ConnectStyle::TransactionsFirstReorgsOnlyTip,
+                               8 => ConnectStyle::FullBlockViaListen,
                                _ => unreachable!(),
                        };
                        eprintln!("Using Block Connection Style: {:?}", res);
@@ -143,6 +153,7 @@ impl ConnectStyle {
 pub fn connect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, depth: u32) -> BlockHash {
        let skip_intermediaries = match *node.connect_style.borrow() {
                ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks|
+                       ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks|ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks|
                        ConnectStyle::BestBlockFirstReorgsOnlyTip|ConnectStyle::TransactionsFirstReorgsOnlyTip => true,
                _ => false,
        };
@@ -193,8 +204,32 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: Block, sk
                                node.node.best_block_updated(&block.header, height);
                                node.node.transactions_confirmed(&block.header, &txdata, height);
                        },
-                       ConnectStyle::TransactionsFirst|ConnectStyle::TransactionsFirstSkippingBlocks|ConnectStyle::TransactionsFirstReorgsOnlyTip => {
+                       ConnectStyle::TransactionsFirst|ConnectStyle::TransactionsFirstSkippingBlocks|
+                       ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks|ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks|
+                       ConnectStyle::TransactionsFirstReorgsOnlyTip => {
+                               if *node.connect_style.borrow() == ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks {
+                                       let mut connections = Vec::new();
+                                       for (block, height) in node.blocks.lock().unwrap().iter() {
+                                               if !block.txdata.is_empty() {
+                                                       // Reconnect all transactions we've ever seen to ensure transaction connection
+                                                       // is *really* idempotent. This is a somewhat likely deployment for some
+                                                       // esplora implementations of chain sync which try to reduce state and
+                                                       // complexity as much as possible.
+                                                       //
+                                                       // Sadly we have to clone the block here to maintain lockorder. In the
+                                                       // future we should consider Arc'ing the blocks to avoid this.
+                                                       connections.push((block.clone(), *height));
+                                               }
+                                       }
+                                       for (old_block, height) in connections {
+                                               node.chain_monitor.chain_monitor.transactions_confirmed(&old_block.header,
+                                                       &old_block.txdata.iter().enumerate().collect::<Vec<_>>(), height);
+                                       }
+                               }
                                node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height);
+                               if *node.connect_style.borrow() == ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks {
+                                       node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height);
+                               }
                                call_claimable_balances(node);
                                node.chain_monitor.chain_monitor.best_block_updated(&block.header, height);
                                node.node.transactions_confirmed(&block.header, &txdata, height);
@@ -226,7 +261,8 @@ pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32)
                                node.chain_monitor.chain_monitor.block_disconnected(&orig.0.header, orig.1);
                                Listen::block_disconnected(node.node, &orig.0.header, orig.1);
                        },
-                       ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks => {
+                       ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks|
+                       ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks|ConnectStyle::TransactionsDuplicativelyFirstSkippingBlocks => {
                                if i == count - 1 {
                                        node.chain_monitor.chain_monitor.best_block_updated(&prev.0.header, prev.1);
                                        node.node.best_block_updated(&prev.0.header, prev.1);
@@ -806,10 +842,12 @@ pub fn create_chan_between_nodes_with_value_init<'a, 'b, 'c>(node_a: &Node<'a, '
        let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None).unwrap();
        let open_channel_msg = get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id());
        assert_eq!(open_channel_msg.temporary_channel_id, create_chan_id);
+       assert_eq!(node_a.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 42);
        node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), a_flags, &open_channel_msg);
        let accept_channel_msg = get_event_msg!(node_b, MessageSendEvent::SendAcceptChannel, node_a.node.get_our_node_id());
        assert_eq!(accept_channel_msg.temporary_channel_id, create_chan_id);
        node_a.node.handle_accept_channel(&node_b.node.get_our_node_id(), b_flags, &accept_channel_msg);
+       assert_ne!(node_b.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 0);
 
        sign_funding_transaction(node_a, node_b, channel_value, create_chan_id)
 }
@@ -1431,20 +1469,20 @@ macro_rules! expect_pending_htlcs_forwardable_from_events {
                }
        }}
 }
-
 #[macro_export]
 #[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
 macro_rules! expect_payment_received {
        ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr) => {
-               expect_payment_received!($node, $expected_payment_hash, $expected_payment_secret, $expected_recv_value, None)
+               expect_payment_received!($node, $expected_payment_hash, $expected_payment_secret, $expected_recv_value, None, $node.node.get_our_node_id())
        };
-       ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr, $expected_payment_preimage: expr) => {
+       ($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr, $expected_payment_preimage: expr, $expected_receiver_node_id: expr) => {
                let events = $node.node.get_and_clear_pending_events();
                assert_eq!(events.len(), 1);
                match events[0] {
-                       $crate::util::events::Event::PaymentReceived { ref payment_hash, ref purpose, amount_msat } => {
+                       $crate::util::events::Event::PaymentReceived { ref payment_hash, ref purpose, amount_msat, receiver_node_id } => {
                                assert_eq!($expected_payment_hash, *payment_hash);
                                assert_eq!($expected_recv_value, amount_msat);
+                               assert_eq!($expected_receiver_node_id, receiver_node_id.unwrap());
                                match purpose {
                                        $crate::util::events::PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
                                                assert_eq!(&$expected_payment_preimage, payment_preimage);
@@ -1736,8 +1774,9 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p
                        if payment_received_expected {
                                assert_eq!(events_2.len(), 1);
                                match events_2[0] {
-                                       Event::PaymentReceived { ref payment_hash, ref purpose, amount_msat } => {
+                                       Event::PaymentReceived { ref payment_hash, ref purpose, amount_msat, receiver_node_id } => {
                                                assert_eq!(our_payment_hash, *payment_hash);
+                                               assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap());
                                                match &purpose {
                                                        PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
                                                                assert_eq!(expected_preimage, *payment_preimage);
@@ -2411,6 +2450,14 @@ macro_rules! handle_chan_reestablish_msgs {
                                assert_eq!(*node_id, $dst_node.node.get_our_node_id());
                        }
 
+                       let mut had_channel_update = false; // ChannelUpdate may be now or later, but not both
+                       if let Some(&MessageSendEvent::SendChannelUpdate { ref node_id, ref msg }) = msg_events.get(idx) {
+                               assert_eq!(*node_id, $dst_node.node.get_our_node_id());
+                               idx += 1;
+                               assert_eq!(msg.contents.flags & 2, 0); // "disabled" flag must not be set as we just reconnected.
+                               had_channel_update = true;
+                       }
+
                        let mut revoke_and_ack = None;
                        let mut commitment_update = None;
                        let order = if let Some(ev) = msg_events.get(idx) {
@@ -2455,6 +2502,7 @@ macro_rules! handle_chan_reestablish_msgs {
                                assert_eq!(*node_id, $dst_node.node.get_our_node_id());
                                idx += 1;
                                assert_eq!(msg.contents.flags & 2, 0); // "disabled" flag must not be set as we just reconnected.
+                               assert!(!had_channel_update);
                        }
 
                        assert_eq!(msg_events.len(), idx);