diff --git a/lightning-liquidity/tests/common/mod.rs b/lightning-liquidity/tests/common/mod.rs index ebf2afdaadd..3a31ab99ea7 100644 --- a/lightning-liquidity/tests/common/mod.rs +++ b/lightning-liquidity/tests/common/mod.rs @@ -1,632 +1,84 @@ #![cfg(test)] -// TODO: remove these flags and unused code once we know what we'll need. -#![allow(dead_code)] -#![allow(unused_imports)] -#![allow(unused_macros)] -use lightning::chain::Filter; -use lightning::sign::{EntropySource, NodeSigner}; - -use bitcoin::blockdata::constants::{genesis_block, ChainHash}; -use bitcoin::blockdata::transaction::Transaction; use bitcoin::Network; -use lightning::chain::channelmonitor::ANTI_REORG_DELAY; -use lightning::chain::{chainmonitor, BestBlock, Confirm}; -use lightning::ln::channelmanager; use lightning::ln::channelmanager::ChainParameters; -use lightning::ln::functional_test_utils::*; -use lightning::ln::msgs::{BaseMessageHandler, ChannelMessageHandler, Init}; -use lightning::ln::peer_handler::{ - IgnoringMessageHandler, MessageHandler, PeerManager, SocketDescriptor, -}; - -use lightning::onion_message::messenger::DefaultMessageRouter; -use lightning::routing::gossip::{NetworkGraph, P2PGossipSync}; -use lightning::routing::router::{CandidateRouteHop, DefaultRouter, Path}; -use lightning::routing::scoring::{ChannelUsage, ScoreLookUp, ScoreUpdate}; -use lightning::sign::{InMemorySigner, KeysManager}; -use lightning::util::config::UserConfig; -use lightning::util::persist::{ - KVStore, CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, - CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, NETWORK_GRAPH_PERSISTENCE_KEY, - NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, - SCORER_PERSISTENCE_KEY, SCORER_PERSISTENCE_PRIMARY_NAMESPACE, - SCORER_PERSISTENCE_SECONDARY_NAMESPACE, -}; -use lightning::util::test_utils; use lightning_liquidity::{LiquidityClientConfig, LiquidityManager, LiquidityServiceConfig}; -use lightning_persister::fs_store::FilesystemStore; -use std::collections::{HashMap, VecDeque}; -use std::path::PathBuf; -use std::sync::atomic::AtomicBool; -use std::sync::mpsc::SyncSender; -use std::sync::{Arc, Mutex}; -use std::time::Duration; -use std::{env, fs}; +use lightning::chain::{BestBlock, Filter}; +use lightning::ln::functional_test_utils::{Node, TestChannelManager}; +use lightning::util::test_utils::TestKeysInterface; -pub(crate) struct TestEntropy {} -impl EntropySource for TestEntropy { - fn get_secure_random_bytes(&self) -> [u8; 32] { - [0; 32] - } -} +use core::ops::Deref; -#[derive(Clone, Hash, PartialEq, Eq)] -pub(crate) struct TestDescriptor {} -impl SocketDescriptor for TestDescriptor { - fn send_data(&mut self, _data: &[u8], _resume_read: bool) -> usize { - 0 - } +use std::sync::Arc; - fn disconnect_socket(&mut self) {} +pub(crate) struct LSPSNodes<'a, 'b, 'c> { + pub service_node: LiquidityNode<'a, 'b, 'c>, + pub client_node: LiquidityNode<'a, 'b, 'c>, } -#[cfg(c_bindings)] -type LockingWrapper = lightning::routing::scoring::MultiThreadedLockableScore; -#[cfg(not(c_bindings))] -type LockingWrapper = std::sync::Mutex; - -type ChannelManager = channelmanager::ChannelManager< - Arc, - Arc, - Arc, - Arc, - Arc, - Arc, - Arc< - DefaultRouter< - Arc>>, - Arc, - Arc, - Arc>, - (), - TestScorer, - >, - >, - Arc< - DefaultMessageRouter< - Arc>>, - Arc, - Arc, - >, - >, - Arc, ->; - -type ChainMonitor = chainmonitor::ChainMonitor< - InMemorySigner, - Arc, - Arc, - Arc, - Arc, - Arc, - Arc, ->; - -type PGS = Arc< - P2PGossipSync< - Arc>>, - Arc, - Arc, - >, ->; - -pub(crate) struct Node { - pub(crate) channel_manager: Arc, - pub(crate) keys_manager: Arc, - pub(crate) p2p_gossip_sync: PGS, - pub(crate) peer_manager: Arc< - PeerManager< - TestDescriptor, - Arc, - Arc, - IgnoringMessageHandler, - Arc, - Arc< - LiquidityManager< - Arc, - Arc, - Arc, - >, - >, - Arc, - Arc, - >, - >, - pub(crate) liquidity_manager: - Arc, Arc, Arc>>, - pub(crate) chain_monitor: Arc, - pub(crate) kv_store: Arc, - pub(crate) tx_broadcaster: Arc, - pub(crate) network_graph: Arc>>, - pub(crate) logger: Arc, - pub(crate) best_block: BestBlock, - pub(crate) scorer: Arc>, -} - -impl Drop for Node { - fn drop(&mut self) { - let data_dir = self.kv_store.get_data_dir(); - match fs::remove_dir_all(data_dir.clone()) { - Err(e) => { - println!("Failed to remove test store directory {}: {}", data_dir.display(), e) - }, - _ => {}, - } - } -} - -struct Persister { - graph_error: Option<(lightning::io::ErrorKind, &'static str)>, - graph_persistence_notifier: Option>, - manager_error: Option<(lightning::io::ErrorKind, &'static str)>, - scorer_error: Option<(lightning::io::ErrorKind, &'static str)>, - kv_store: FilesystemStore, -} - -impl Persister { - fn new(data_dir: PathBuf) -> Self { - let kv_store = FilesystemStore::new(data_dir); - Self { - graph_error: None, - graph_persistence_notifier: None, - manager_error: None, - scorer_error: None, - kv_store, - } - } - - fn with_graph_error(self, error: lightning::io::ErrorKind, message: &'static str) -> Self { - Self { graph_error: Some((error, message)), ..self } - } - - fn with_graph_persistence_notifier(self, sender: SyncSender<()>) -> Self { - Self { graph_persistence_notifier: Some(sender), ..self } - } - - fn with_manager_error(self, error: lightning::io::ErrorKind, message: &'static str) -> Self { - Self { manager_error: Some((error, message)), ..self } - } - - fn with_scorer_error(self, error: lightning::io::ErrorKind, message: &'static str) -> Self { - Self { scorer_error: Some((error, message)), ..self } - } -} - -impl KVStore for Persister { - fn read( - &self, primary_namespace: &str, secondary_namespace: &str, key: &str, - ) -> lightning::io::Result> { - self.kv_store.read(primary_namespace, secondary_namespace, key) - } - - fn write( - &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: &[u8], - ) -> lightning::io::Result<()> { - if primary_namespace == CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE - && secondary_namespace == CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE - && key == CHANNEL_MANAGER_PERSISTENCE_KEY - { - if let Some((error, message)) = self.manager_error { - return Err(lightning::io::Error::new(error, message)); - } - } - - if primary_namespace == NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE - && secondary_namespace == NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE - && key == NETWORK_GRAPH_PERSISTENCE_KEY - { - if let Some(sender) = &self.graph_persistence_notifier { - match sender.send(()) { - Ok(()) => {}, - Err(std::sync::mpsc::SendError(())) => { - println!("Persister failed to notify as receiver went away.") - }, - } - }; - - if let Some((error, message)) = self.graph_error { - return Err(lightning::io::Error::new(error, message)); - } - } - - if primary_namespace == SCORER_PERSISTENCE_PRIMARY_NAMESPACE - && secondary_namespace == SCORER_PERSISTENCE_SECONDARY_NAMESPACE - && key == SCORER_PERSISTENCE_KEY - { - if let Some((error, message)) = self.scorer_error { - return Err(lightning::io::Error::new(error, message)); - } - } - - self.kv_store.write(primary_namespace, secondary_namespace, key, buf) - } - - fn remove( - &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, - ) -> lightning::io::Result<()> { - self.kv_store.remove(primary_namespace, secondary_namespace, key, lazy) - } - - fn list( - &self, primary_namespace: &str, secondary_namespace: &str, - ) -> lightning::io::Result> { - self.kv_store.list(primary_namespace, secondary_namespace) - } -} - -pub(crate) struct TestScorer { - event_expectations: Option>, -} - -#[derive(Debug)] -pub(crate) enum TestResult { - PaymentFailure { path: Path, short_channel_id: u64 }, - PaymentSuccess { path: Path }, - ProbeFailure { path: Path }, - ProbeSuccess { path: Path }, -} - -impl TestScorer { - fn new() -> Self { - Self { event_expectations: None } - } - - fn expect(&mut self, expectation: TestResult) { - self.event_expectations.get_or_insert_with(VecDeque::new).push_back(expectation); - } -} - -impl lightning::util::ser::Writeable for TestScorer { - fn write( - &self, _: &mut W, - ) -> Result<(), lightning::io::Error> { - Ok(()) - } -} - -impl ScoreLookUp for TestScorer { - type ScoreParams = (); - fn channel_penalty_msat( - &self, _candidate: &CandidateRouteHop, _usage: ChannelUsage, - _score_params: &Self::ScoreParams, - ) -> u64 { - unimplemented!(); - } -} - -impl ScoreUpdate for TestScorer { - fn payment_path_failed( - &mut self, actual_path: &Path, actual_short_channel_id: u64, _: Duration, - ) { - if let Some(expectations) = &mut self.event_expectations { - match expectations.pop_front().unwrap() { - TestResult::PaymentFailure { path, short_channel_id } => { - assert_eq!(actual_path, &path); - assert_eq!(actual_short_channel_id, short_channel_id); - }, - TestResult::PaymentSuccess { path } => { - panic!("Unexpected successful payment path: {:?}", path) - }, - TestResult::ProbeFailure { path } => { - panic!("Unexpected probe failure: {:?}", path) - }, - TestResult::ProbeSuccess { path } => { - panic!("Unexpected probe success: {:?}", path) - }, - } - } - } - - fn payment_path_successful(&mut self, actual_path: &Path, _: Duration) { - if let Some(expectations) = &mut self.event_expectations { - match expectations.pop_front().unwrap() { - TestResult::PaymentFailure { path, .. } => { - panic!("Unexpected payment path failure: {:?}", path) - }, - TestResult::PaymentSuccess { path } => { - assert_eq!(actual_path, &path); - }, - TestResult::ProbeFailure { path } => { - panic!("Unexpected probe failure: {:?}", path) - }, - TestResult::ProbeSuccess { path } => { - panic!("Unexpected probe success: {:?}", path) - }, - } - } - } - - fn probe_failed(&mut self, actual_path: &Path, _: u64, _: Duration) { - if let Some(expectations) = &mut self.event_expectations { - match expectations.pop_front().unwrap() { - TestResult::PaymentFailure { path, .. } => { - panic!("Unexpected payment path failure: {:?}", path) - }, - TestResult::PaymentSuccess { path } => { - panic!("Unexpected payment path success: {:?}", path) - }, - TestResult::ProbeFailure { path } => { - assert_eq!(actual_path, &path); - }, - TestResult::ProbeSuccess { path } => { - panic!("Unexpected probe success: {:?}", path) - }, - } - } - } - fn probe_successful(&mut self, actual_path: &Path, _: Duration) { - if let Some(expectations) = &mut self.event_expectations { - match expectations.pop_front().unwrap() { - TestResult::PaymentFailure { path, .. } => { - panic!("Unexpected payment path failure: {:?}", path) - }, - TestResult::PaymentSuccess { path } => { - panic!("Unexpected payment path success: {:?}", path) - }, - TestResult::ProbeFailure { path } => { - panic!("Unexpected probe failure: {:?}", path) - }, - TestResult::ProbeSuccess { path } => { - assert_eq!(actual_path, &path); - }, - } - } - } - fn time_passed(&mut self, _: Duration) {} -} - -#[cfg(c_bindings)] -impl lightning::routing::scoring::Score for TestScorer {} - -impl Drop for TestScorer { - fn drop(&mut self) { - if std::thread::panicking() { - return; - } - - if let Some(event_expectations) = &self.event_expectations { - if !event_expectations.is_empty() { - panic!("Unsatisfied event expectations: {:?}", event_expectations); - } - } - } -} - -fn get_full_filepath(filepath: String, filename: String) -> String { - let mut path = PathBuf::from(filepath); - path.push(filename); - path.to_str().unwrap().to_string() -} - -pub(crate) fn create_liquidity_node( - i: usize, persist_dir: &str, network: Network, service_config: Option, - client_config: Option, -) -> Node { - let tx_broadcaster = Arc::new(test_utils::TestBroadcaster::new(network)); - let fee_estimator = Arc::new(test_utils::TestFeeEstimator::new(253)); - let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i))); - let genesis_block = genesis_block(network); - let network_graph = Arc::new(NetworkGraph::new(network, Arc::clone(&logger))); - let scorer = Arc::new(LockingWrapper::new(TestScorer::new())); - let now = Duration::from_secs(genesis_block.header.time as u64); - let seed = [i as u8; 32]; - let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos())); - let router = Arc::new(DefaultRouter::new( - Arc::clone(&network_graph), - Arc::clone(&logger), - Arc::clone(&keys_manager), - Arc::clone(&scorer), - Default::default(), - )); - let msg_router = - Arc::new(DefaultMessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager))); - let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Bitcoin)); - let kv_store = - Arc::new(FilesystemStore::new(format!("{}_persister_{}", &persist_dir, i).into())); - let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new( - Some(Arc::clone(&chain_source)), - Arc::clone(&tx_broadcaster), - Arc::clone(&logger), - Arc::clone(&fee_estimator), - Arc::clone(&kv_store), - Arc::clone(&keys_manager), - keys_manager.get_peer_storage_key(), - )); - let best_block = BestBlock::from_network(network); - let chain_params = ChainParameters { network, best_block }; - let channel_manager = Arc::new(ChannelManager::new( - Arc::clone(&fee_estimator), - Arc::clone(&chain_monitor), - Arc::clone(&tx_broadcaster), - Arc::clone(&router), - Arc::clone(&msg_router), - Arc::clone(&logger), - Arc::clone(&keys_manager), - Arc::clone(&keys_manager), - Arc::clone(&keys_manager), - UserConfig::default(), - chain_params, - genesis_block.header.time, - )); - let p2p_gossip_sync = Arc::new(P2PGossipSync::new( - Arc::clone(&network_graph), - Some(Arc::clone(&chain_source)), - Arc::clone(&logger), - )); - - let liquidity_manager = Arc::new(LiquidityManager::new( - Arc::clone(&keys_manager), - Arc::clone(&channel_manager), +pub(crate) fn create_service_and_client_nodes<'a, 'b, 'c>( + nodes: Vec>, service_config: LiquidityServiceConfig, + client_config: LiquidityClientConfig, +) -> LSPSNodes<'a, 'b, 'c> { + let chain_params = ChainParameters { + network: Network::Testnet, + best_block: BestBlock::from_network(Network::Testnet), + }; + let service_lm = LiquidityManager::new( + nodes[0].keys_manager, + nodes[0].node, + None::>, + Some(chain_params.clone()), + Some(service_config), + None, + ); + + let client_lm = LiquidityManager::new( + nodes[1].keys_manager, + nodes[1].node, None::>, Some(chain_params), - service_config, - client_config, - )); - let msg_handler = MessageHandler { - chan_handler: Arc::new(test_utils::TestChannelMessageHandler::new( - ChainHash::using_genesis_block(Network::Testnet), - )), - route_handler: Arc::new(test_utils::TestRoutingMessageHandler::new()), - onion_message_handler: IgnoringMessageHandler {}, - custom_message_handler: Arc::clone(&liquidity_manager), - send_only_message_handler: Arc::clone(&chain_monitor), - }; - let peer_manager = - PeerManager::new(msg_handler, 0, &seed, Arc::clone(&logger), Arc::clone(&keys_manager)); - - Node { - channel_manager, - keys_manager, - p2p_gossip_sync, - peer_manager: Arc::new(peer_manager), - liquidity_manager, - chain_monitor, - kv_store, - tx_broadcaster, - network_graph, - logger, - best_block, - scorer, - } -} - -pub(crate) fn create_service_and_client_nodes( - persist_dir: &str, service_config: LiquidityServiceConfig, client_config: LiquidityClientConfig, -) -> (Node, Node) { - let persist_temp_path = env::temp_dir().join(persist_dir); - let persist_dir = persist_temp_path.to_string_lossy().to_string(); - let network = Network::Bitcoin; - - let service_node = create_liquidity_node(1, &persist_dir, network, Some(service_config), None); - let client_node = create_liquidity_node(2, &persist_dir, network, None, Some(client_config)); + None, + Some(client_config), + ); - service_node - .channel_manager - .peer_connected( - client_node.channel_manager.get_our_node_id(), - &Init { - features: client_node.channel_manager.init_features(), - networks: None, - remote_network_address: None, - }, - true, - ) - .unwrap(); - client_node - .channel_manager - .peer_connected( - service_node.channel_manager.get_our_node_id(), - &Init { - features: service_node.channel_manager.init_features(), - networks: None, - remote_network_address: None, - }, - true, - ) - .unwrap(); + let mut iter = nodes.into_iter(); + let service_node = LiquidityNode::new(iter.next().unwrap(), service_lm); + let client_node = LiquidityNode::new(iter.next().unwrap(), client_lm); - (service_node, client_node) + LSPSNodes { service_node, client_node } } -macro_rules! open_channel { - ($node_a: expr, $node_b: expr, $channel_value: expr) => {{ - begin_open_channel!($node_a, $node_b, $channel_value); - let events = $node_a.node.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - let (temporary_channel_id, tx) = - handle_funding_generation_ready!(events[0], $channel_value); - $node_a - .node - .funding_transaction_generated( - &temporary_channel_id, - &$node_b.node.get_our_node_id(), - tx.clone(), - ) - .unwrap(); - $node_b.node.handle_funding_created( - &$node_a.node.get_our_node_id(), - &get_event_msg!( - $node_a, - MessageSendEvent::SendFundingCreated, - $node_b.node.get_our_node_id() - ), - ); - get_event!($node_b, Event::ChannelPending); - $node_a.node.handle_funding_signed( - &$node_b.node.get_our_node_id(), - &get_event_msg!( - $node_b, - MessageSendEvent::SendFundingSigned, - $node_a.node.get_our_node_id() - ), - ); - get_event!($node_a, Event::ChannelPending); - tx - }}; +pub(crate) struct LiquidityNode<'a, 'b, 'c> { + pub inner: Node<'a, 'b, 'c>, + pub liquidity_manager: LiquidityManager< + &'c TestKeysInterface, + &'a TestChannelManager<'b, 'c>, + Arc, + >, } -pub(crate) use open_channel; - -macro_rules! begin_open_channel { - ($node_a: expr, $node_b: expr, $channel_value: expr) => {{ - $node_a - .node - .create_channel($node_b.node.get_our_node_id(), $channel_value, 100, 42, None, None) - .unwrap(); - $node_b.node.handle_open_channel( - &$node_a.node.get_our_node_id(), - &get_event_msg!( - $node_a, - MessageSendEvent::SendOpenChannel, - $node_b.node.get_our_node_id() - ), - ); - $node_a.node.handle_accept_channel( - &$node_b.node.get_our_node_id(), - &get_event_msg!( - $node_b, - MessageSendEvent::SendAcceptChannel, - $node_a.node.get_our_node_id() - ), - ); - }}; +impl<'a, 'b, 'c> LiquidityNode<'a, 'b, 'c> { + pub fn new( + node: Node<'a, 'b, 'c>, + liquidity_manager: LiquidityManager< + &'c TestKeysInterface, + &'a TestChannelManager<'b, 'c>, + Arc, + >, + ) -> Self { + Self { inner: node, liquidity_manager } + } } -pub(crate) use begin_open_channel; - -macro_rules! handle_funding_generation_ready { - ($event: expr, $channel_value: expr) => {{ - match $event { - Event::FundingGenerationReady { - temporary_channel_id, - channel_value_satoshis, - ref output_script, - user_channel_id, - .. - } => { - assert_eq!(channel_value_satoshis, $channel_value); - assert_eq!(user_channel_id, 42); - - let tx = Transaction { - version: 1 as i32, - lock_time: LockTime::ZERO, - input: Vec::new(), - output: vec![TxOut { - value: channel_value_satoshis, - script_pubkey: output_script.clone(), - }], - }; - (temporary_channel_id, tx) - }, - _ => panic!("Unexpected event"), - } - }}; +impl<'a, 'b, 'c> Deref for LiquidityNode<'a, 'b, 'c> { + type Target = Node<'a, 'b, 'c>; + fn deref(&self) -> &Self::Target { + &self.inner + } } -pub(crate) use handle_funding_generation_ready; - macro_rules! get_lsps_message { ($node: expr, $expected_target_node_id: expr) => {{ let msgs = $node.liquidity_manager.get_and_clear_pending_msg(); @@ -638,41 +90,3 @@ macro_rules! get_lsps_message { } pub(crate) use get_lsps_message; - -fn confirm_transaction_depth(node: &mut Node, tx: &Transaction, depth: u32) { - for i in 1..=depth { - let prev_blockhash = node.best_block.block_hash; - let height = node.best_block.height + 1; - let header = create_dummy_header(prev_blockhash, height); - let txdata = vec![(0, tx)]; - node.best_block = BestBlock::new(header.block_hash(), height); - match i { - 1 => { - node.channel_manager.transactions_confirmed(&header, &txdata, height); - node.chain_monitor.transactions_confirmed(&header, &txdata, height); - }, - x if x == depth => { - node.channel_manager.best_block_updated(&header, height); - node.chain_monitor.best_block_updated(&header, height); - }, - _ => {}, - } - } -} - -fn confirm_transaction(node: &mut Node, tx: &Transaction) { - confirm_transaction_depth(node, tx, ANTI_REORG_DELAY); -} - -fn advance_chain(node: &mut Node, num_blocks: u32) { - for i in 1..=num_blocks { - let prev_blockhash = node.best_block.block_hash; - let height = node.best_block.height + 1; - let header = create_dummy_header(prev_blockhash, height); - node.best_block = BestBlock::new(header.block_hash(), height); - if i == num_blocks { - node.channel_manager.best_block_updated(&header, height); - node.chain_monitor.best_block_updated(&header, height); - } - } -} diff --git a/lightning-liquidity/tests/lsps0_integration_tests.rs b/lightning-liquidity/tests/lsps0_integration_tests.rs index 50444971746..465ab029d53 100644 --- a/lightning-liquidity/tests/lsps0_integration_tests.rs +++ b/lightning-liquidity/tests/lsps0_integration_tests.rs @@ -2,7 +2,7 @@ mod common; -use common::{create_service_and_client_nodes, get_lsps_message}; +use common::{create_service_and_client_nodes, get_lsps_message, LSPSNodes}; use lightning_liquidity::events::LiquidityEvent; use lightning_liquidity::lsps0::event::LSPS0ClientEvent; @@ -14,10 +14,18 @@ use lightning_liquidity::lsps2::client::LSPS2ClientConfig; use lightning_liquidity::lsps2::service::LSPS2ServiceConfig; use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig}; +use lightning::ln::functional_test_utils::{ + create_chanmon_cfgs, create_network, create_node_cfgs, create_node_chanmgrs, +}; use lightning::ln::peer_handler::CustomMessageHandler; #[test] fn list_protocols_integration_test() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); let promise_secret = [42; 32]; let lsps2_service_config = LSPS2ServiceConfig { promise_secret }; #[cfg(lsps1_service)] @@ -40,16 +48,13 @@ fn list_protocols_integration_test() { lsps2_client_config: Some(lsps2_client_config), }; - let (service_node, client_node) = create_service_and_client_nodes( - "list_protocols_integration_test", - service_config, - client_config, - ); + let service_node_id = nodes[0].node.get_our_node_id(); + let client_node_id = nodes[1].node.get_our_node_id(); - let service_node_id = service_node.channel_manager.get_our_node_id(); + let LSPSNodes { service_node, client_node } = + create_service_and_client_nodes(nodes, service_config, client_config); let client_handler = client_node.liquidity_manager.lsps0_client_handler(); - let client_node_id = client_node.channel_manager.get_our_node_id(); client_handler.list_protocols(&service_node_id); let list_protocols_request = get_lsps_message!(client_node, service_node_id); diff --git a/lightning-liquidity/tests/lsps2_integration_tests.rs b/lightning-liquidity/tests/lsps2_integration_tests.rs index a2721cab1de..02266807992 100644 --- a/lightning-liquidity/tests/lsps2_integration_tests.rs +++ b/lightning-liquidity/tests/lsps2_integration_tests.rs @@ -2,8 +2,7 @@ mod common; -use common::create_service_and_client_nodes; -use common::{get_lsps_message, Node}; +use common::{create_service_and_client_nodes, get_lsps_message, LSPSNodes, LiquidityNode}; use lightning_liquidity::events::LiquidityEvent; use lightning_liquidity::lsps0::ser::LSPSDateTime; @@ -13,17 +12,22 @@ use lightning_liquidity::lsps2::event::LSPS2ServiceEvent; use lightning_liquidity::lsps2::msgs::LSPS2RawOpeningFeeParams; use lightning_liquidity::lsps2::service::LSPS2ServiceConfig; use lightning_liquidity::lsps2::utils::is_valid_opening_fee_params; +use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig}; use lightning::ln::channelmanager::{InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA}; +use lightning::ln::functional_test_utils::{ + create_chanmon_cfgs, create_node_cfgs, create_node_chanmgrs, +}; +use lightning::ln::functional_test_utils::{create_network, Node}; use lightning::ln::peer_handler::CustomMessageHandler; use lightning::log_error; use lightning::routing::router::{RouteHint, RouteHintHop}; +use lightning::sign::NodeSigner; use lightning::util::errors::APIError; use lightning::util::logger::Logger; use lightning_invoice::{Bolt11Invoice, InvoiceBuilder, RoutingFees}; -use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig}; use lightning_types::payment::PaymentHash; use bitcoin::hashes::{sha256, Hash}; @@ -36,11 +40,10 @@ use std::time::Duration; const MAX_PENDING_REQUESTS_PER_PEER: usize = 10; const MAX_TOTAL_PENDING_REQUESTS: usize = 1000; -fn setup_test_lsps2( - persist_dir: &str, -) -> (bitcoin::secp256k1::PublicKey, bitcoin::secp256k1::PublicKey, Node, Node, [u8; 32]) { +fn setup_test_lsps2_nodes<'a, 'b, 'c>( + nodes: Vec>, +) -> (LSPSNodes<'a, 'b, 'c>, [u8; 32]) { let promise_secret = [42; 32]; - let signing_key = SecretKey::from_slice(&promise_secret).unwrap(); let lsps2_service_config = LSPS2ServiceConfig { promise_secret }; let service_config = LiquidityServiceConfig { #[cfg(lsps1_service)] @@ -54,29 +57,22 @@ fn setup_test_lsps2( lsps1_client_config: None, lsps2_client_config: Some(lsps2_client_config), }; + let lsps_nodes = create_service_and_client_nodes(nodes, service_config, client_config); - let (service_node, client_node) = - create_service_and_client_nodes(persist_dir, service_config, client_config); - - let secp = bitcoin::secp256k1::Secp256k1::new(); - let service_node_id = bitcoin::secp256k1::PublicKey::from_secret_key(&secp, &signing_key); - let client_node_id = client_node.channel_manager.get_our_node_id(); - - (service_node_id, client_node_id, service_node, client_node, promise_secret) + (lsps_nodes, promise_secret) } fn create_jit_invoice( - node: &Node, service_node_id: PublicKey, intercept_scid: u64, cltv_expiry_delta: u32, - payment_size_msat: Option, description: &str, expiry_secs: u32, + node: &LiquidityNode<'_, '_, '_>, service_node_id: PublicKey, intercept_scid: u64, + cltv_expiry_delta: u32, payment_size_msat: Option, description: &str, expiry_secs: u32, ) -> Result { // LSPS2 requires min_final_cltv_expiry_delta to be at least 2 more than usual. let min_final_cltv_expiry_delta = MIN_FINAL_CLTV_EXPIRY_DELTA + 2; let (payment_hash, payment_secret) = node - .channel_manager + .node .create_inbound_payment(None, expiry_secs, Some(min_final_cltv_expiry_delta)) .map_err(|e| { log_error!(node.logger, "Failed to register inbound payment: {:?}", e); - () })?; let route_hint = RouteHint(vec![RouteHintHop { @@ -90,7 +86,6 @@ fn create_jit_invoice( let payment_hash = sha256::Hash::from_slice(&payment_hash.0).map_err(|e| { log_error!(node.logger, "Invalid payment hash: {:?}", e); - () })?; let currency = Network::Bitcoin.into(); @@ -107,20 +102,30 @@ fn create_jit_invoice( invoice_builder = invoice_builder.amount_milli_satoshis(amount_msat).basic_mpp(); } - invoice_builder - .build_signed(|hash| { - Secp256k1::new().sign_ecdsa_recoverable(hash, &node.keys_manager.get_node_secret_key()) - }) - .map_err(|e| { - log_error!(node.logger, "Failed to build and sign invoice: {}", e); - () + let raw_invoice = invoice_builder.build_raw().map_err(|e| { + log_error!(node.inner.logger, "Failed to build raw invoice: {:?}", e); + })?; + + let sign_fn = + node.inner.keys_manager.sign_invoice(&raw_invoice, lightning::sign::Recipient::Node); + + raw_invoice.sign(|_| sign_fn).and_then(|signed_raw| { + Bolt11Invoice::from_signed(signed_raw).map_err(|e| { + log_error!(node.inner.logger, "Failed to create invoice from signed raw: {:?}", e); }) + }) } #[test] fn invoice_generation_flow() { - let (service_node_id, client_node_id, service_node, client_node, promise_secret) = - setup_test_lsps2("invoice_generation_flow"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, promise_secret) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + let service_node_id = service_node.inner.node.get_our_node_id(); + let client_node_id = client_node.inner.node.get_our_node_id(); let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); @@ -210,7 +215,7 @@ fn invoice_generation_flow() { let user_channel_id = 42; let cltv_expiry_delta = 144; - let intercept_scid = service_node.channel_manager.get_intercept_scid(); + let intercept_scid = service_node.node.get_intercept_scid(); let client_trusts_lsp = true; service_handler @@ -261,8 +266,15 @@ fn invoice_generation_flow() { #[test] fn channel_open_failed() { - let (service_node_id, client_node_id, service_node, client_node, _) = - setup_test_lsps2("channel_open_failed"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + + let service_node_id = service_node.inner.node.get_our_node_id(); + let client_node_id = client_node.inner.node.get_our_node_id(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap(); @@ -314,7 +326,7 @@ fn channel_open_failed() { let _buy_event = service_node.liquidity_manager.next_event().unwrap(); let user_channel_id = 42; let cltv_expiry_delta = 144; - let intercept_scid = service_node.channel_manager.get_intercept_scid(); + let intercept_scid = service_node.node.get_intercept_scid(); let client_trusts_lsp = true; service_handler @@ -389,8 +401,14 @@ fn channel_open_failed() { #[test] fn channel_open_failed_nonexistent_channel() { - let (_, client_node_id, service_node, _, _) = - setup_test_lsps2("channel_open_failed_nonexistent_channel"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + + let client_node_id = client_node.inner.node.get_our_node_id(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); @@ -409,8 +427,15 @@ fn channel_open_failed_nonexistent_channel() { #[test] fn channel_open_abandoned() { - let (service_node_id, client_node_id, service_node, client_node, _) = - setup_test_lsps2("channel_open_abandoned"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + + let service_node_id = service_node.inner.node.get_our_node_id(); + let client_node_id = client_node.inner.node.get_our_node_id(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap(); @@ -462,7 +487,7 @@ fn channel_open_abandoned() { let _buy_event = service_node.liquidity_manager.next_event().unwrap(); let user_channel_id = 42; let cltv_expiry_delta = 144; - let intercept_scid = service_node.channel_manager.get_intercept_scid(); + let intercept_scid = service_node.node.get_intercept_scid(); let client_trusts_lsp = true; service_handler @@ -486,8 +511,14 @@ fn channel_open_abandoned() { #[test] fn channel_open_abandoned_nonexistent_channel() { - let (_, client_node_id, service_node, _, _) = - setup_test_lsps2("channel_open_abandoned_nonexistent_channel"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + + let client_node_id = client_node.inner.node.get_our_node_id(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); // Call channel_open_abandoned with a nonexistent user_channel_id @@ -505,8 +536,15 @@ fn channel_open_abandoned_nonexistent_channel() { #[test] fn max_pending_requests_per_peer_rejected() { - let (service_node_id, client_node_id, service_node, client_node, _) = - setup_test_lsps2("max_pending_requests_per_peer_rejected"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + + let service_node_id = service_node.inner.node.get_our_node_id(); + let client_node_id = client_node.inner.node.get_our_node_id(); let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap(); @@ -553,8 +591,14 @@ fn max_pending_requests_per_peer_rejected() { #[test] fn max_total_requests_buy_rejected() { - let (service_node_id, _, service_node, client_node, _) = - setup_test_lsps2("max_total_requests_buy_rejected"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + + let service_node_id = service_node.inner.node.get_our_node_id(); let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); @@ -676,9 +720,15 @@ fn max_total_requests_buy_rejected() { #[test] fn invalid_token_flow() { - let (service_node_id, client_node_id, service_node, client_node, _promise_secret) = - setup_test_lsps2("invalid_token_flow"); - + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + + let service_node_id = service_node.inner.node.get_our_node_id(); + let client_node_id = client_node.inner.node.get_our_node_id(); let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); @@ -749,8 +799,14 @@ fn invalid_token_flow() { #[test] fn opening_fee_params_menu_is_sorted_by_spec() { - let (service_node_id, client_node_id, service_node, client_node, _secret) = - setup_test_lsps2("opening_fee_params_menu_is_sorted_by_spec"); + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let (lsps_nodes, _) = setup_test_lsps2_nodes(nodes); + let LSPSNodes { service_node, client_node } = lsps_nodes; + let service_node_id = service_node.inner.node.get_our_node_id(); + let client_node_id = client_node.inner.node.get_our_node_id(); let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap(); let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap(); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index dac63c8b33f..9c40d6d4377 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -486,7 +486,7 @@ pub struct NodeCfg<'a> { pub override_init_features: Rc>>, } -pub(crate) type TestChannelManager<'node_cfg, 'chan_mon_cfg> = ChannelManager< +pub type TestChannelManager<'node_cfg, 'chan_mon_cfg> = ChannelManager< &'node_cfg TestChainMonitor<'chan_mon_cfg>, &'chan_mon_cfg test_utils::TestBroadcaster, &'node_cfg test_utils::TestKeysInterface,