X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_test_utils.rs;h=cd3041be8d32dda0a13e49ce2b2a98df744632ca;hb=64b9e83dfed1979adecab83f6efcf10f95ecf987;hp=6b247b28f097d30b9576b13c6fa435343ecf4fd1;hpb=17e1403856933f9649413a179325eaea25da825e;p=rust-lightning diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 6b247b28..cd3041be 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -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::>(), 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); @@ -1433,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); @@ -1738,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);