From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Thu, 1 Apr 2021 21:38:03 +0000 (+0000) Subject: Merge pull request #860 from TheBlueMatt/2021-03-bench-sends X-Git-Tag: v0.0.14~40 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=df732f4a6decc355626554d8bc0c7c8bccbe59e7;hp=7665b148427c7d7b11b59bcb4bb17c8fb2000d05;p=rust-lightning Merge pull request #860 from TheBlueMatt/2021-03-bench-sends Add a simple send-funds benchmark in channelmanager --- diff --git a/lightning-persister/Cargo.toml b/lightning-persister/Cargo.toml index 0a9821f14..a6e7242b0 100644 --- a/lightning-persister/Cargo.toml +++ b/lightning-persister/Cargo.toml @@ -8,6 +8,9 @@ description = """ Utilities to manage Rust-Lightning channel data persistence and retrieval. """ +[features] +unstable = ["lightning/unstable"] + [dependencies] bitcoin = "0.26" lightning = { version = "0.0.13", path = "../lightning" } diff --git a/lightning-persister/src/lib.rs b/lightning-persister/src/lib.rs index afcda8033..44586422c 100644 --- a/lightning-persister/src/lib.rs +++ b/lightning-persister/src/lib.rs @@ -3,6 +3,9 @@ #![deny(broken_intra_doc_links)] #![deny(missing_docs)] +#![cfg_attr(all(test, feature = "unstable"), feature(test))] +#[cfg(all(test, feature = "unstable"))] extern crate test; + mod util; extern crate lightning; @@ -330,3 +333,15 @@ mod tests { added_monitors.clear(); } } + +#[cfg(all(test, feature = "unstable"))] +pub mod bench { + use test::Bencher; + + #[bench] + fn bench_sends(bench: &mut Bencher) { + let persister_a = super::FilesystemPersister::new("bench_filesystem_persister_a".to_string()); + let persister_b = super::FilesystemPersister::new("bench_filesystem_persister_b".to_string()); + lightning::ln::channelmanager::bench::bench_two_sends(bench, persister_a, persister_b); + } +} diff --git a/lightning/src/lib.rs b/lightning/src/lib.rs index 2d764c8b7..9bf947045 100644 --- a/lightning/src/lib.rs +++ b/lightning/src/lib.rs @@ -28,8 +28,8 @@ #![allow(bare_trait_objects)] #![allow(ellipsis_inclusive_range_patterns)] -#![cfg_attr(all(test, feature = "unstable"), feature(test))] -#[cfg(all(test, feature = "unstable"))] extern crate test; +#![cfg_attr(all(any(test, feature = "_test_utils"), feature = "unstable"), feature(test))] +#[cfg(all(any(test, feature = "_test_utils"), feature = "unstable"))] extern crate test; extern crate bitcoin; #[cfg(any(test, feature = "_test_utils"))] extern crate hex; diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 50f8ccbb7..19fdd97a6 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -434,6 +434,7 @@ pub struct ChannelManager>, our_network_key: SecretKey, + our_network_pubkey: PublicKey, /// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this /// value increases strictly since we don't assume access to a time source. @@ -822,7 +823,6 @@ impl ChannelMana latest_block_height: AtomicUsize::new(params.latest_height), last_block_hash: RwLock::new(params.latest_hash), - secp_ctx, channel_state: Mutex::new(ChannelHolder{ by_id: HashMap::new(), @@ -832,6 +832,8 @@ impl ChannelMana pending_msg_events: Vec::new(), }), our_network_key: keys_manager.get_node_secret(), + our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()), + secp_ctx, last_node_announcement_serial: AtomicUsize::new(0), @@ -2315,7 +2317,7 @@ impl ChannelMana /// Gets the node_id held by this ChannelManager pub fn get_our_node_id(&self) -> PublicKey { - PublicKey::from_secret_key(&self.secp_ctx, &self.our_network_key) + self.our_network_pubkey.clone() } /// Restores a single, given channel to normal operation after a @@ -4318,7 +4320,6 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> latest_block_height: AtomicUsize::new(latest_block_height as usize), last_block_hash: RwLock::new(last_block_hash), - secp_ctx, channel_state: Mutex::new(ChannelHolder { by_id, @@ -4328,6 +4329,8 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> pending_msg_events: Vec::new(), }), our_network_key: args.keys_manager.get_node_secret(), + our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()), + secp_ctx, last_node_announcement_serial: AtomicUsize::new(last_node_announcement_serial as usize), @@ -4404,3 +4407,154 @@ mod tests { } } } + +#[cfg(all(any(test, feature = "_test_utils"), feature = "unstable"))] +pub mod bench { + use chain::Listen; + use chain::chainmonitor::ChainMonitor; + use chain::channelmonitor::Persist; + use chain::keysinterface::{KeysManager, InMemorySigner}; + use chain::transaction::OutPoint; + use ln::channelmanager::{ChainParameters, ChannelManager, PaymentHash, PaymentPreimage}; + use ln::features::InitFeatures; + use ln::functional_test_utils::*; + use ln::msgs::ChannelMessageHandler; + use routing::network_graph::NetworkGraph; + use routing::router::get_route; + use util::test_utils; + use util::config::UserConfig; + use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider}; + + use bitcoin::hashes::Hash; + use bitcoin::hashes::sha256::Hash as Sha256; + use bitcoin::{Block, BlockHeader, Transaction, TxOut}; + + use std::sync::Mutex; + + use test::Bencher; + + struct NodeHolder<'a, P: Persist> { + node: &'a ChannelManager, + &'a test_utils::TestBroadcaster, &'a KeysManager, + &'a test_utils::TestFeeEstimator, &'a test_utils::TestLogger> + } + + #[cfg(test)] + #[bench] + fn bench_sends(bench: &mut Bencher) { + bench_two_sends(bench, test_utils::TestPersister::new(), test_utils::TestPersister::new()); + } + + pub fn bench_two_sends>(bench: &mut Bencher, persister_a: P, persister_b: P) { + // Do a simple benchmark of sending a payment back and forth between two nodes. + // Note that this is unrealistic as each payment send will require at least two fsync + // calls per node. + let network = bitcoin::Network::Testnet; + let genesis_hash = bitcoin::blockdata::constants::genesis_block(network).header.block_hash(); + + let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())}; + let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 }; + + let mut config: UserConfig = Default::default(); + config.own_channel_config.minimum_depth = 1; + + let logger_a = test_utils::TestLogger::with_id("node a".to_owned()); + let chain_monitor_a = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_a); + let seed_a = [1u8; 32]; + let keys_manager_a = KeysManager::new(&seed_a, 42, 42); + let node_a = ChannelManager::new(&fee_estimator, &chain_monitor_a, &tx_broadcaster, &logger_a, &keys_manager_a, config.clone(), ChainParameters { + network, + latest_hash: genesis_hash, + latest_height: 0, + }); + let node_a_holder = NodeHolder { node: &node_a }; + + let logger_b = test_utils::TestLogger::with_id("node a".to_owned()); + let chain_monitor_b = ChainMonitor::new(None, &tx_broadcaster, &logger_a, &fee_estimator, &persister_b); + let seed_b = [2u8; 32]; + let keys_manager_b = KeysManager::new(&seed_b, 42, 42); + let node_b = ChannelManager::new(&fee_estimator, &chain_monitor_b, &tx_broadcaster, &logger_b, &keys_manager_b, config.clone(), ChainParameters { + network, + latest_hash: genesis_hash, + latest_height: 0, + }); + let node_b_holder = NodeHolder { node: &node_b }; + + node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None).unwrap(); + node_b.handle_open_channel(&node_a.get_our_node_id(), InitFeatures::known(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id())); + node_a.handle_accept_channel(&node_b.get_our_node_id(), InitFeatures::known(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id())); + + let tx; + if let Event::FundingGenerationReady { temporary_channel_id, output_script, .. } = get_event!(node_a_holder, Event::FundingGenerationReady) { + tx = Transaction { version: 2, lock_time: 0, input: Vec::new(), output: vec![TxOut { + value: 8_000_000, script_pubkey: output_script, + }]}; + let funding_outpoint = OutPoint { txid: tx.txid(), index: 0 }; + node_a.funding_transaction_generated(&temporary_channel_id, funding_outpoint); + } else { panic!(); } + + node_b.handle_funding_created(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendFundingCreated, node_b.get_our_node_id())); + node_a.handle_funding_signed(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendFundingSigned, node_a.get_our_node_id())); + + get_event!(node_a_holder, Event::FundingBroadcastSafe); + + let block = Block { + header: BlockHeader { version: 0x20000000, prev_blockhash: genesis_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }, + txdata: vec![tx], + }; + Listen::block_connected(&node_a, &block, 1); + Listen::block_connected(&node_b, &block, 1); + + node_a.handle_funding_locked(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendFundingLocked, node_a.get_our_node_id())); + node_b.handle_funding_locked(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendFundingLocked, node_b.get_our_node_id())); + + let dummy_graph = NetworkGraph::new(genesis_hash); + + macro_rules! send_payment { + ($node_a: expr, $node_b: expr) => { + let usable_channels = $node_a.list_usable_channels(); + let route = get_route(&$node_a.get_our_node_id(), &dummy_graph, &$node_b.get_our_node_id(), None, Some(&usable_channels.iter().map(|r| r).collect::>()), &[], 10_000, TEST_FINAL_CLTV, &logger_a).unwrap(); + + let payment_preimage = PaymentPreimage([0; 32]); + let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()); + + $node_a.send_payment(&route, payment_hash, &None).unwrap(); + let payment_event = SendEvent::from_event($node_a.get_and_clear_pending_msg_events().pop().unwrap()); + $node_b.handle_update_add_htlc(&$node_a.get_our_node_id(), &payment_event.msgs[0]); + $node_b.handle_commitment_signed(&$node_a.get_our_node_id(), &payment_event.commitment_msg); + let (raa, cs) = get_revoke_commit_msgs!(NodeHolder { node: &$node_b }, $node_a.get_our_node_id()); + $node_a.handle_revoke_and_ack(&$node_b.get_our_node_id(), &raa); + $node_a.handle_commitment_signed(&$node_b.get_our_node_id(), &cs); + $node_b.handle_revoke_and_ack(&$node_a.get_our_node_id(), &get_event_msg!(NodeHolder { node: &$node_a }, MessageSendEvent::SendRevokeAndACK, $node_b.get_our_node_id())); + + expect_pending_htlcs_forwardable!(NodeHolder { node: &$node_b }); + expect_payment_received!(NodeHolder { node: &$node_b }, payment_hash, 10_000); + assert!($node_b.claim_funds(payment_preimage, &None, 10_000)); + + match $node_b.get_and_clear_pending_msg_events().pop().unwrap() { + MessageSendEvent::UpdateHTLCs { node_id, updates } => { + assert_eq!(node_id, $node_a.get_our_node_id()); + $node_a.handle_update_fulfill_htlc(&$node_b.get_our_node_id(), &updates.update_fulfill_htlcs[0]); + $node_a.handle_commitment_signed(&$node_b.get_our_node_id(), &updates.commitment_signed); + }, + _ => panic!("Failed to generate claim event"), + } + + let (raa, cs) = get_revoke_commit_msgs!(NodeHolder { node: &$node_a }, $node_b.get_our_node_id()); + $node_b.handle_revoke_and_ack(&$node_a.get_our_node_id(), &raa); + $node_b.handle_commitment_signed(&$node_a.get_our_node_id(), &cs); + $node_a.handle_revoke_and_ack(&$node_b.get_our_node_id(), &get_event_msg!(NodeHolder { node: &$node_b }, MessageSendEvent::SendRevokeAndACK, $node_a.get_our_node_id())); + + expect_payment_sent!(NodeHolder { node: &$node_a }, payment_preimage); + } + } + + bench.iter(|| { + send_payment!(node_a, node_b); + send_payment!(node_b, node_a); + }); + } +} diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 36ca7d64e..3c641dd74 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -313,6 +313,24 @@ macro_rules! get_event_msg { } } +/// Get a specific event from the pending events queue. +#[macro_export] +macro_rules! get_event { + ($node: expr, $event_type: path) => { + { + let mut events = $node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + let ev = events.pop().unwrap(); + match ev { + $event_type { .. } => { + ev + }, + _ => panic!("Unexpected event"), + } + } + } +} + #[cfg(test)] macro_rules! get_htlc_update_msgs { ($node: expr, $node_id: expr) => { @@ -848,7 +866,7 @@ macro_rules! expect_pending_htlcs_forwardable { }} } -#[cfg(test)] +#[cfg(any(test, feature = "unstable"))] macro_rules! expect_payment_received { ($node: expr, $expected_payment_hash: expr, $expected_recv_value: expr) => { let events = $node.node.get_and_clear_pending_events(); diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 1afcb3530..3827cea84 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -18,6 +18,10 @@ //! you want to learn things about the network topology (eg get a route for sending a payment), //! call into your NetGraphMsgHandler. +#[cfg(any(test, feature = "_test_utils"))] +#[macro_use] +pub mod functional_test_utils; + pub mod channelmanager; pub mod msgs; pub mod peer_handler; @@ -38,9 +42,6 @@ mod wire; // without the node parameter being mut. This is incorrect, and thus newer rustcs will complain // about an unnecessary mut. Thus, we silence the unused_mut warning in two test modules below. -#[cfg(any(test, feature = "_test_utils"))] -#[macro_use] -pub mod functional_test_utils; #[cfg(test)] #[allow(unused_mut)] mod functional_tests; diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 2d3f930a0..153f2f28e 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -186,12 +186,12 @@ impl TestPersister { *self.update_ret.lock().unwrap() = ret; } } -impl channelmonitor::Persist for TestPersister { - fn persist_new_channel(&self, _funding_txo: OutPoint, _data: &channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { +impl channelmonitor::Persist for TestPersister { + fn persist_new_channel(&self, _funding_txo: OutPoint, _data: &channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { self.update_ret.lock().unwrap().clone() } - fn update_persisted_channel(&self, _funding_txo: OutPoint, _update: &channelmonitor::ChannelMonitorUpdate, _data: &channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { + fn update_persisted_channel(&self, _funding_txo: OutPoint, _update: &channelmonitor::ChannelMonitorUpdate, _data: &channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { self.update_ret.lock().unwrap().clone() } }