From d9cefaabc0194ecdf3db854f8f107eae6c7d01d7 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Thu, 18 Jun 2026 10:44:57 -0500 Subject: [PATCH] Require PaginatedKVStore for all stores Now that all of our KVStore impl's also impl PaginatedKVStore we can require it when building a node. One caveat being that our upgrade downgrade test no longer works given that these new PaginatedKVStores don't support downgrading to their old, non paginated versions. Because of this we are commenting it out and will bring it back once we tag 0.8 --- src/builder.rs | 20 +- src/types.rs | 56 ++- tests/common/mod.rs | 48 +- tests/upgrade_downgrade_tests.rs | 806 ++++++++++++++++--------------- 4 files changed, 514 insertions(+), 416 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 3df594b7c..d142f51af 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -37,8 +37,8 @@ use lightning::routing::scoring::{ use lightning::sign::{EntropySource, NodeSigner}; use lightning::util::config::HTLCInterceptionFlags; use lightning::util::persist::{ - KVStore, CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, - CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, + KVStore, PaginatedKVStore, CHANNEL_MANAGER_PERSISTENCE_KEY, + CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, }; use lightning::util::ser::ReadableArgs; use lightning::util::sweep::OutputSweeper; @@ -254,7 +254,7 @@ impl std::error::Error for BuildError {} /// - [`build`] uses an SQLite database (recommended default). /// - [`build_with_fs_store`] uses a filesystem-based store. /// - [`build_with_vss_store`] and variants use a [VSS] remote store (**experimental**). -/// - [`build_with_store`] allows providing a custom [`KVStore`] implementation. +/// - [`build_with_store`] allows providing a custom [`PaginatedKVStore`] implementation. /// /// ### Logging /// @@ -270,7 +270,7 @@ impl std::error::Error for BuildError {} /// [`build_with_vss_store`]: Self::build_with_vss_store /// [`build_with_store`]: Self::build_with_store /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md -/// [`KVStore`]: lightning::util::persist::KVStore +/// [`PaginatedKVStore`]: lightning::util::persist::PaginatedKVStore /// [`DEFAULT_LOG_LEVEL`]: crate::config::DEFAULT_LOG_LEVEL /// [`set_filesystem_logger`]: Self::set_filesystem_logger /// [`set_log_facade_logger`]: Self::set_log_facade_logger @@ -813,7 +813,7 @@ impl NodeBuilder { } /// Builds a [`Node`] instance according to the options previously configured. - pub fn build_with_store( + pub fn build_with_store( &self, node_entropy: NodeEntropy, kv_store: S, ) -> Result { let logger = setup_logger(&self.log_writer_config, &self.config)?; @@ -832,14 +832,14 @@ impl NodeBuilder { } } - fn build_with_store_and_logger( + fn build_with_store_and_logger( &self, node_entropy: NodeEntropy, kv_store: S, logger: Arc, ) -> Result { let runtime = self.setup_runtime(&logger)?; self.build_with_store_runtime_and_logger(node_entropy, kv_store, runtime, logger) } - fn build_with_store_runtime_and_logger( + fn build_with_store_runtime_and_logger( &self, node_entropy: NodeEntropy, kv_store: S, runtime: Arc, logger: Arc, ) -> Result { let seed_bytes = node_entropy.to_seed_bytes(); @@ -876,7 +876,7 @@ impl NodeBuilder { /// - [`build`] uses an SQLite database (recommended default). /// - [`build_with_fs_store`] uses a filesystem-based store. /// - [`build_with_vss_store`] and variants use a [VSS] remote store (**experimental**). -/// - [`build_with_store`] allows providing a custom [`KVStore`] implementation. +/// - [`build_with_store`] allows providing a custom [`PaginatedKVStore`] implementation. /// /// ### Logging /// @@ -892,7 +892,7 @@ impl NodeBuilder { /// [`build_with_vss_store`]: Self::build_with_vss_store /// [`build_with_store`]: Self::build_with_store /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md -/// [`KVStore`]: lightning::util::persist::KVStore +/// [`PaginatedKVStore`]: lightning::util::persist::PaginatedKVStore /// [`DEFAULT_LOG_LEVEL`]: crate::config::DEFAULT_LOG_LEVEL /// [`set_filesystem_logger`]: Self::set_filesystem_logger /// [`set_log_facade_logger`]: Self::set_log_facade_logger @@ -1330,7 +1330,7 @@ impl ArcedNodeBuilder { /// Builds a [`Node`] instance according to the options previously configured. // Note that the generics here don't actually work for Uniffi, but we don't currently expose // this so its not needed. - pub fn build_with_store( + pub fn build_with_store( &self, node_entropy: Arc, kv_store: S, ) -> Result, BuildError> { self.inner.read().expect("lock").build_with_store(*node_entropy, kv_store).map(Arc::new) diff --git a/src/types.rs b/src/types.rs index 64209430b..9854e35bf 100644 --- a/src/types.rs +++ b/src/types.rs @@ -29,7 +29,9 @@ use lightning::routing::gossip; use lightning::routing::router::DefaultRouter; use lightning::routing::scoring::{CombinedScorer, ProbabilisticScoringFeeParameters}; use lightning::sign::InMemorySigner; -use lightning::util::persist::{KVStore, MonitorUpdatingPersisterAsync}; +use lightning::util::persist::{ + KVStore, MonitorUpdatingPersisterAsync, PageToken, PaginatedKVStore, PaginatedListResponse, +}; use lightning::util::ser::{Readable, Writeable, Writer}; use lightning::util::sweep::OutputSweeper; use lightning_block_sync::gossip::GossipVerifier; @@ -59,6 +61,13 @@ pub(crate) trait DynStoreTrait: Send + Sync { fn list_async( &self, primary_namespace: &str, secondary_namespace: &str, ) -> Pin, bitcoin::io::Error>> + Send + 'static>>; + fn list_paginated_async( + &self, primary_namespace: &str, secondary_namespace: &str, page_token: Option, + ) -> Pin< + Box< + dyn Future> + Send + 'static, + >, + >; } impl<'a> KVStore for dyn DynStoreTrait + 'a { @@ -87,6 +96,19 @@ impl<'a> KVStore for dyn DynStoreTrait + 'a { } } +impl<'a> PaginatedKVStore for dyn DynStoreTrait + 'a { + fn list_paginated( + &self, primary_namespace: &str, secondary_namespace: &str, page_token: Option, + ) -> impl Future> + Send + 'static { + DynStoreTrait::list_paginated_async( + self, + primary_namespace, + secondary_namespace, + page_token, + ) + } +} + pub(crate) type DynStore = dyn DynStoreTrait; // Newtype wrapper that implements `KVStore` for `Arc`. This is needed because `KVStore` @@ -122,9 +144,22 @@ impl KVStore for DynStoreRef { } } -pub(crate) struct DynStoreWrapper(pub(crate) T); +impl PaginatedKVStore for DynStoreRef { + fn list_paginated( + &self, primary_namespace: &str, secondary_namespace: &str, page_token: Option, + ) -> impl Future> + Send + 'static { + DynStoreTrait::list_paginated_async( + &*self.0, + primary_namespace, + secondary_namespace, + page_token, + ) + } +} + +pub(crate) struct DynStoreWrapper(pub(crate) T); -impl DynStoreTrait for DynStoreWrapper { +impl DynStoreTrait for DynStoreWrapper { fn read_async( &self, primary_namespace: &str, secondary_namespace: &str, key: &str, ) -> Pin, bitcoin::io::Error>> + Send + 'static>> { @@ -148,6 +183,21 @@ impl DynStoreTrait for DynStoreWrapper { ) -> Pin, bitcoin::io::Error>> + Send + 'static>> { Box::pin(KVStore::list(&self.0, primary_namespace, secondary_namespace)) } + + fn list_paginated_async( + &self, primary_namespace: &str, secondary_namespace: &str, page_token: Option, + ) -> Pin< + Box< + dyn Future> + Send + 'static, + >, + > { + Box::pin(PaginatedKVStore::list_paginated( + &self.0, + primary_namespace, + secondary_namespace, + page_token, + )) + } } pub(crate) type AsyncPersister = MonitorUpdatingPersisterAsync< diff --git a/tests/common/mod.rs b/tests/common/mod.rs index adeb327bf..1f5753e55 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -50,7 +50,7 @@ use ldk_node::{ use lightning::io; use lightning::ln::msgs::SocketAddress; use lightning::routing::gossip::NodeAlias; -use lightning::util::persist::KVStore; +use lightning::util::persist::{KVStore, PageToken, PaginatedKVStore, PaginatedListResponse}; use lightning_invoice::{Bolt11InvoiceDescription, Description}; use lightning_persister::fs_store::v1::FilesystemStore; use lightning_types::payment::{PaymentHash, PaymentPreimage}; @@ -1702,6 +1702,21 @@ impl KVStore for TestSyncStore { } } +impl PaginatedKVStore for TestSyncStore { + fn list_paginated( + &self, primary_namespace: &str, secondary_namespace: &str, page_token: Option, + ) -> impl Future> + 'static + Send { + let primary_namespace = primary_namespace.to_string(); + let secondary_namespace = secondary_namespace.to_string(); + let inner = Arc::clone(&self.inner); + async move { + inner + .list_paginated_internal_async(&primary_namespace, &secondary_namespace, page_token) + .await + } + } +} + struct TestSyncStoreInner { serializer: tokio::sync::RwLock<()>, test_store: InMemoryStore, @@ -1765,6 +1780,37 @@ impl TestSyncStoreInner { self.do_list_async(primary_namespace, secondary_namespace).await } + async fn list_paginated_internal_async( + &self, primary_namespace: &str, secondary_namespace: &str, page_token: Option, + ) -> lightning::io::Result { + let _guard = self.serializer.read().await; + let sqlite_res = PaginatedKVStore::list_paginated( + &self.sqlite_store, + primary_namespace, + secondary_namespace, + page_token.clone(), + ) + .await; + let test_res = PaginatedKVStore::list_paginated( + &self.test_store, + primary_namespace, + secondary_namespace, + page_token, + ) + .await; + + match sqlite_res { + Ok(sqlite_response) => { + assert_eq!(sqlite_response, test_res.unwrap()); + Ok(sqlite_response) + }, + Err(e) => { + assert!(test_res.is_err()); + Err(e) + }, + } + } + async fn read_internal_async( &self, primary_namespace: &str, secondary_namespace: &str, key: &str, ) -> lightning::io::Result> { diff --git a/tests/upgrade_downgrade_tests.rs b/tests/upgrade_downgrade_tests.rs index b30b5a33c..41e47c170 100644 --- a/tests/upgrade_downgrade_tests.rs +++ b/tests/upgrade_downgrade_tests.rs @@ -15,405 +15,407 @@ // understandable by v0.7.0, these tests intentionally write current state through // the legacy v1 filesystem-store implementation via `build_with_store`, then // reopen it with v0.7.0's `build_with_fs_store`. - -#[allow(unused_imports, unused_macros)] -mod common; - -use std::path::PathBuf; -use std::time::Duration; - -use bitcoin::secp256k1::PublicKey; -use bitcoin::Amount; -use common::{ - generate_blocks_and_wait, generate_listening_addresses, premine_and_distribute_funds, - random_storage_path, setup_bitcoind_and_electrsd, wait_for_tx, -}; -use ldk_node::config::{Config, EsploraSyncConfig}; -use ldk_node::entropy::NodeEntropy; -use ldk_node::lightning::ln::msgs::SocketAddress as CurrentSocketAddress; -use ldk_node::lightning_invoice::{ - Bolt11InvoiceDescription as CurrentBolt11InvoiceDescription, Description as CurrentDescription, -}; -use lightning_persister::fs_store::v1::FilesystemStore; - -#[cfg(feature = "uniffi")] -type CurrentNode = std::sync::Arc; -#[cfg(not(feature = "uniffi"))] -type CurrentNode = ldk_node::Node; - -const NODE_A_SEED_BYTES: [u8; 64] = [42; 64]; -const NODE_B_SEED_BYTES: [u8; 64] = [43; 64]; -const FUNDING_AMOUNT_SAT: u64 = 2_000_000; -const CHANNEL_AMOUNT_SAT: u64 = 1_000_000; -const PUSH_AMOUNT_MSAT: u64 = 500_000_000; -const PRE_DOWNGRADE_PAYMENT_MSAT: u64 = 100_000; -const POST_DOWNGRADE_PAYMENT_MSAT: u64 = 200_000; - -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] -async fn monitor_v0_7_0_serialization_downgrade_channel_payment() { - let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); - let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap()); - - let storage_path_a = random_storage_path().to_str().unwrap().to_owned(); - let storage_path_b = random_storage_path().to_str().unwrap().to_owned(); - let current_addresses_a = generate_listening_addresses(); - let current_addresses_b = generate_listening_addresses(); - let v070_addresses_a = to_v070_socket_addresses(¤t_addresses_a); - let v070_addresses_b = to_v070_socket_addresses(¤t_addresses_b); - - let node_id_a; - let node_id_b; - let pre_downgrade_payment_id; - - { - let node_a = build_current_node( - storage_path_a.clone(), - NODE_A_SEED_BYTES, - current_addresses_a.clone(), - "downgrade-a", - &esplora_url, - ); - let node_b = build_current_node( - storage_path_b.clone(), - NODE_B_SEED_BYTES, - current_addresses_b.clone(), - "downgrade-b", - &esplora_url, - ); - node_id_a = node_a.node_id(); - node_id_b = node_b.node_id(); - - let addr_a = node_a.onchain_payment().new_address().unwrap(); - let addr_b = node_b.onchain_payment().new_address().unwrap(); - premine_and_distribute_funds( - &bitcoind.client, - &electrsd.client, - vec![addr_a, addr_b], - Amount::from_sat(FUNDING_AMOUNT_SAT), - ) - .await; - node_a.sync_wallets().unwrap(); - node_b.sync_wallets().unwrap(); - assert_eq!(node_a.list_balances().spendable_onchain_balance_sats, FUNDING_AMOUNT_SAT); - assert_eq!(node_b.list_balances().spendable_onchain_balance_sats, FUNDING_AMOUNT_SAT); - - let funding_txo = open_current_channel(&node_a, &node_b).await; - wait_for_tx(&electrsd.client, funding_txo.txid).await; - generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; - node_a.sync_wallets().unwrap(); - node_b.sync_wallets().unwrap(); - expect_current_channel_ready(&node_a, node_id_b).await; - expect_current_channel_ready(&node_b, node_id_a).await; - assert_current_channel_ready(&node_a, node_id_b); - assert_current_channel_ready(&node_b, node_id_a); - - pre_downgrade_payment_id = send_current_bolt11_payment( - &node_a, - &node_b, - PRE_DOWNGRADE_PAYMENT_MSAT, - "pre-downgrade", - ) - .await; - - node_a.stop().unwrap(); - node_b.stop().unwrap(); - } - - let node_a_v070 = build_v070_node( - storage_path_a, - NODE_A_SEED_BYTES, - v070_addresses_a.clone(), - "downgrade-a", - &esplora_url, - ); - let node_b_v070 = build_v070_node( - storage_path_b, - NODE_B_SEED_BYTES, - v070_addresses_b.clone(), - "downgrade-b", - &esplora_url, - ); - - assert_eq!(node_a_v070.node_id(), node_id_a); - assert_eq!(node_b_v070.node_id(), node_id_b); - - let pre_downgrade_payment_id = - ldk_node_070::lightning::ln::channelmanager::PaymentId(pre_downgrade_payment_id.0); - assert_v070_bolt11_payment( - &node_a_v070, - &pre_downgrade_payment_id, - ldk_node_070::payment::PaymentDirection::Outbound, - PRE_DOWNGRADE_PAYMENT_MSAT, - ); - assert_v070_bolt11_payment( - &node_b_v070, - &pre_downgrade_payment_id, - ldk_node_070::payment::PaymentDirection::Inbound, - PRE_DOWNGRADE_PAYMENT_MSAT, - ); - - node_a_v070.sync_wallets().unwrap(); - node_b_v070.sync_wallets().unwrap(); - node_a_v070.connect(node_id_b, v070_addresses_b.first().unwrap().clone(), true).unwrap(); - wait_for_v070_usable_channel(&node_a_v070, node_id_b).await; - wait_for_v070_usable_channel(&node_b_v070, node_id_a).await; - drain_v070_events(&node_a_v070).await; - drain_v070_events(&node_b_v070).await; - - send_v070_bolt11_payment( - &node_a_v070, - &node_b_v070, - POST_DOWNGRADE_PAYMENT_MSAT, - "post-downgrade", - ) - .await; - - node_a_v070.stop().unwrap(); - node_b_v070.stop().unwrap(); -} - -fn build_current_node( - storage_path: String, seed_bytes: [u8; 64], listening_addresses: Vec, - alias: &str, esplora_url: &str, -) -> CurrentNode { - let mut config = Config::default(); - config.network = bitcoin::Network::Regtest; - config.storage_dir_path = storage_path; - config.listening_addresses = Some(listening_addresses); - config.anchor_channels_config = None; - - // Use the v1 filesystem layout that v0.7.0's filesystem builder can reopen. - let mut fs_store_path = PathBuf::from(&config.storage_dir_path); - fs_store_path.push("fs_store"); - #[allow(unused_mut)] - let mut builder = ldk_node::Builder::from_config(config); - builder.set_node_alias(alias.to_string()).unwrap(); - - let mut sync_config = EsploraSyncConfig::default(); - sync_config.background_sync_config = None; - builder.set_chain_source_esplora(esplora_url.to_owned(), Some(sync_config)); - - #[cfg(feature = "uniffi")] - let node_entropy = std::sync::Arc::new(NodeEntropy::from_seed_bytes(seed_bytes.to_vec()).unwrap()); - #[cfg(not(feature = "uniffi"))] - let node_entropy = NodeEntropy::from_seed_bytes(seed_bytes); - - let kv_store = FilesystemStore::new(fs_store_path); - let node = builder.build_with_store(node_entropy.into(), kv_store).unwrap(); - node.start().unwrap(); - node -} - -fn build_v070_node( - storage_path: String, seed_bytes: [u8; 64], - listening_addresses: Vec, alias: &str, - esplora_url: &str, -) -> ldk_node_070::Node { - let mut builder = ldk_node_070::Builder::new(); - builder.set_network(bitcoin::Network::Regtest); - builder.set_storage_dir_path(storage_path); - builder.set_entropy_seed_bytes(seed_bytes); - builder.set_listening_addresses(listening_addresses).unwrap(); - builder.set_node_alias(alias.to_string()).unwrap(); - builder.set_chain_source_esplora(esplora_url.to_owned(), None); - let node = builder.build_with_fs_store().unwrap(); - node.start().unwrap(); - node -} - -async fn open_current_channel(node_a: &CurrentNode, node_b: &CurrentNode) -> bitcoin::OutPoint { - node_a - .open_channel( - node_b.node_id(), - node_b.listening_addresses().unwrap().first().unwrap().clone(), - CHANNEL_AMOUNT_SAT, - Some(PUSH_AMOUNT_MSAT), - None, - ) - .unwrap(); - - let funding_txo_a = expect_current_channel_pending(node_a, node_b.node_id()).await; - let funding_txo_b = expect_current_channel_pending(node_b, node_a.node_id()).await; - assert_eq!(funding_txo_a, funding_txo_b); - funding_txo_a -} - -async fn send_current_bolt11_payment( - payer: &CurrentNode, payee: &CurrentNode, amount_msat: u64, description: &str, -) -> ldk_node::lightning::ln::channelmanager::PaymentId { - let invoice_description = CurrentBolt11InvoiceDescription::Direct( - CurrentDescription::new(description.to_owned()).unwrap(), - ); - let invoice = payee - .bolt11_payment() - .receive(amount_msat, &invoice_description.clone().into(), 3600) - .unwrap(); - let payment_id = payer.bolt11_payment().send(&invoice, None).unwrap(); - expect_current_payment_successful(payer, &payment_id).await; - expect_current_payment_received(payee, amount_msat).await; - assert_eq!( - payer.payment(&payment_id).unwrap().status, - ldk_node::payment::PaymentStatus::Succeeded - ); - payment_id -} - -async fn send_v070_bolt11_payment( - payer: &ldk_node_070::Node, payee: &ldk_node_070::Node, amount_msat: u64, description: &str, -) { - let invoice_description = ldk_node_070::lightning_invoice::Bolt11InvoiceDescription::Direct( - ldk_node_070::lightning_invoice::Description::new(description.to_owned()).unwrap(), - ); - let invoice = payee.bolt11_payment().receive(amount_msat, &invoice_description, 3600).unwrap(); - let payment_id = payer.bolt11_payment().send(&invoice, None).unwrap(); - expect_v070_payment_successful(payer, &payment_id).await; - expect_v070_payment_received(payee, amount_msat).await; - assert_eq!( - payer.payment(&payment_id).unwrap().status, - ldk_node_070::payment::PaymentStatus::Succeeded - ); -} - -async fn expect_current_channel_pending( - node: &CurrentNode, expected_counterparty: PublicKey, -) -> bitcoin::OutPoint { - match next_current_event(node).await { - ldk_node::Event::ChannelPending { counterparty_node_id, funding_txo, .. } => { - assert_eq!(counterparty_node_id, expected_counterparty); - node.event_handled().unwrap(); - funding_txo - }, - event => panic!("{} got unexpected event: {:?}", node.node_id(), event), - } -} - -async fn expect_current_channel_ready(node: &CurrentNode, expected_counterparty: PublicKey) { - match next_current_event(node).await { - ldk_node::Event::ChannelReady { counterparty_node_id, .. } => { - assert_eq!(counterparty_node_id, Some(expected_counterparty)); - node.event_handled().unwrap(); - }, - event => panic!("{} got unexpected event: {:?}", node.node_id(), event), - } -} - -async fn expect_current_payment_successful( - node: &CurrentNode, expected_payment_id: &ldk_node::lightning::ln::channelmanager::PaymentId, -) { - match next_current_event(node).await { - ldk_node::Event::PaymentSuccessful { payment_id, .. } => { - assert_eq!(payment_id.as_ref(), Some(expected_payment_id)); - node.event_handled().unwrap(); - }, - event => panic!("{} got unexpected event: {:?}", node.node_id(), event), - } -} - -async fn expect_current_payment_received(node: &CurrentNode, expected_amount_msat: u64) { - match next_current_event(node).await { - ldk_node::Event::PaymentReceived { amount_msat, payment_id, .. } => { - assert_eq!(amount_msat, expected_amount_msat); - assert!(payment_id.is_some()); - node.event_handled().unwrap(); - }, - event => panic!("{} got unexpected event: {:?}", node.node_id(), event), - } -} - -async fn expect_v070_payment_successful( - node: &ldk_node_070::Node, - expected_payment_id: &ldk_node_070::lightning::ln::channelmanager::PaymentId, -) { - match next_v070_event(node).await { - ldk_node_070::Event::PaymentSuccessful { payment_id, .. } => { - assert_eq!(payment_id.as_ref(), Some(expected_payment_id)); - node.event_handled().unwrap(); - }, - event => panic!("{} got unexpected event: {:?}", node.node_id(), event), - } -} - -async fn expect_v070_payment_received(node: &ldk_node_070::Node, expected_amount_msat: u64) { - match next_v070_event(node).await { - ldk_node_070::Event::PaymentReceived { amount_msat, payment_id, .. } => { - assert_eq!(amount_msat, expected_amount_msat); - assert!(payment_id.is_some()); - node.event_handled().unwrap(); - }, - event => panic!("{} got unexpected event: {:?}", node.node_id(), event), - } -} - -async fn next_current_event(node: &CurrentNode) -> ldk_node::Event { - tokio::time::timeout(Duration::from_secs(common::INTEROP_TIMEOUT_SECS), node.next_event_async()) - .await - .unwrap_or_else(|_| panic!("{} timed out waiting for event", node.node_id())) -} - -async fn next_v070_event(node: &ldk_node_070::Node) -> ldk_node_070::Event { - tokio::time::timeout(Duration::from_secs(common::INTEROP_TIMEOUT_SECS), node.next_event_async()) - .await - .unwrap_or_else(|_| panic!("{} timed out waiting for event", node.node_id())) -} - -async fn drain_v070_events(node: &ldk_node_070::Node) { - while tokio::time::timeout(Duration::from_millis(250), node.next_event_async()).await.is_ok() { - node.event_handled().unwrap(); - } -} - -async fn wait_for_v070_usable_channel(node: &ldk_node_070::Node, counterparty_node_id: PublicKey) { - for _ in 0..40 { - let channels = node.list_channels(); - if let Some(channel) = - channels.iter().find(|c| c.counterparty_node_id == counterparty_node_id) - { - assert_eq!(channel.channel_value_sats, CHANNEL_AMOUNT_SAT); - if channel.is_channel_ready && channel.is_usable { - return; - } - } - tokio::time::sleep(Duration::from_millis(250)).await; - } - - panic!( - "{} failed to restore a usable v0.7.0 channel with {}", - node.node_id(), - counterparty_node_id - ); -} - -fn assert_current_channel_ready(node: &CurrentNode, counterparty_node_id: PublicKey) { - let channels = node.list_channels(); - let channel = channels.iter().find(|c| c.counterparty_node_id == counterparty_node_id).unwrap(); - assert_eq!(channel.channel_value_sats, CHANNEL_AMOUNT_SAT); - assert!(channel.is_channel_ready); -} - -fn assert_v070_bolt11_payment( - node: &ldk_node_070::Node, payment_id: &ldk_node_070::lightning::ln::channelmanager::PaymentId, - expected_direction: ldk_node_070::payment::PaymentDirection, expected_amount_msat: u64, -) { - let payment = node.payment(payment_id).unwrap(); - assert_eq!(payment.amount_msat, Some(expected_amount_msat)); - assert_eq!(payment.direction, expected_direction); - assert_eq!(payment.status, ldk_node_070::payment::PaymentStatus::Succeeded); - assert!(matches!(payment.kind, ldk_node_070::payment::PaymentKind::Bolt11 { .. })); -} - -fn to_v070_socket_addresses( - addresses: &[CurrentSocketAddress], -) -> Vec { - addresses - .iter() - .map(|address| match address { - CurrentSocketAddress::TcpIpV4 { addr, port } => { - ldk_node_070::lightning::ln::msgs::SocketAddress::TcpIpV4 { - addr: *addr, - port: *port, - } - }, - _ => panic!("unexpected non-IPv4 test address: {:?}", address), - }) - .collect() -} +// +// TODO(@benthecarman) Bring back after 0.8 is cut +// +// #[allow(unused_imports, unused_macros)] +// mod common; +// +// use std::path::PathBuf; +// use std::time::Duration; +// +// use bitcoin::secp256k1::PublicKey; +// use bitcoin::Amount; +// use common::{ +// generate_blocks_and_wait, generate_listening_addresses, premine_and_distribute_funds, +// random_storage_path, setup_bitcoind_and_electrsd, wait_for_tx, +// }; +// use ldk_node::config::{Config, EsploraSyncConfig}; +// use ldk_node::entropy::NodeEntropy; +// use ldk_node::lightning::ln::msgs::SocketAddress as CurrentSocketAddress; +// use ldk_node::lightning_invoice::{ +// Bolt11InvoiceDescription as CurrentBolt11InvoiceDescription, Description as CurrentDescription, +// }; +// use lightning_persister::fs_store::v1::FilesystemStore; +// +// #[cfg(feature = "uniffi")] +// type CurrentNode = std::sync::Arc; +// #[cfg(not(feature = "uniffi"))] +// type CurrentNode = ldk_node::Node; +// +// const NODE_A_SEED_BYTES: [u8; 64] = [42; 64]; +// const NODE_B_SEED_BYTES: [u8; 64] = [43; 64]; +// const FUNDING_AMOUNT_SAT: u64 = 2_000_000; +// const CHANNEL_AMOUNT_SAT: u64 = 1_000_000; +// const PUSH_AMOUNT_MSAT: u64 = 500_000_000; +// const PRE_DOWNGRADE_PAYMENT_MSAT: u64 = 100_000; +// const POST_DOWNGRADE_PAYMENT_MSAT: u64 = 200_000; +// +// #[tokio::test(flavor = "multi_thread", worker_threads = 1)] +// async fn monitor_v0_7_0_serialization_downgrade_channel_payment() { +// let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); +// let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap()); +// +// let storage_path_a = random_storage_path().to_str().unwrap().to_owned(); +// let storage_path_b = random_storage_path().to_str().unwrap().to_owned(); +// let current_addresses_a = generate_listening_addresses(); +// let current_addresses_b = generate_listening_addresses(); +// let v070_addresses_a = to_v070_socket_addresses(¤t_addresses_a); +// let v070_addresses_b = to_v070_socket_addresses(¤t_addresses_b); +// +// let node_id_a; +// let node_id_b; +// let pre_downgrade_payment_id; +// +// { +// let node_a = build_current_node( +// storage_path_a.clone(), +// NODE_A_SEED_BYTES, +// current_addresses_a.clone(), +// "downgrade-a", +// &esplora_url, +// ); +// let node_b = build_current_node( +// storage_path_b.clone(), +// NODE_B_SEED_BYTES, +// current_addresses_b.clone(), +// "downgrade-b", +// &esplora_url, +// ); +// node_id_a = node_a.node_id(); +// node_id_b = node_b.node_id(); +// +// let addr_a = node_a.onchain_payment().new_address().unwrap(); +// let addr_b = node_b.onchain_payment().new_address().unwrap(); +// premine_and_distribute_funds( +// &bitcoind.client, +// &electrsd.client, +// vec![addr_a, addr_b], +// Amount::from_sat(FUNDING_AMOUNT_SAT), +// ) +// .await; +// node_a.sync_wallets().unwrap(); +// node_b.sync_wallets().unwrap(); +// assert_eq!(node_a.list_balances().spendable_onchain_balance_sats, FUNDING_AMOUNT_SAT); +// assert_eq!(node_b.list_balances().spendable_onchain_balance_sats, FUNDING_AMOUNT_SAT); +// +// let funding_txo = open_current_channel(&node_a, &node_b).await; +// wait_for_tx(&electrsd.client, funding_txo.txid).await; +// generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await; +// node_a.sync_wallets().unwrap(); +// node_b.sync_wallets().unwrap(); +// expect_current_channel_ready(&node_a, node_id_b).await; +// expect_current_channel_ready(&node_b, node_id_a).await; +// assert_current_channel_ready(&node_a, node_id_b); +// assert_current_channel_ready(&node_b, node_id_a); +// +// pre_downgrade_payment_id = send_current_bolt11_payment( +// &node_a, +// &node_b, +// PRE_DOWNGRADE_PAYMENT_MSAT, +// "pre-downgrade", +// ) +// .await; +// +// node_a.stop().unwrap(); +// node_b.stop().unwrap(); +// } +// +// let node_a_v070 = build_v070_node( +// storage_path_a, +// NODE_A_SEED_BYTES, +// v070_addresses_a.clone(), +// "downgrade-a", +// &esplora_url, +// ); +// let node_b_v070 = build_v070_node( +// storage_path_b, +// NODE_B_SEED_BYTES, +// v070_addresses_b.clone(), +// "downgrade-b", +// &esplora_url, +// ); +// +// assert_eq!(node_a_v070.node_id(), node_id_a); +// assert_eq!(node_b_v070.node_id(), node_id_b); +// +// let pre_downgrade_payment_id = +// ldk_node_070::lightning::ln::channelmanager::PaymentId(pre_downgrade_payment_id.0); +// assert_v070_bolt11_payment( +// &node_a_v070, +// &pre_downgrade_payment_id, +// ldk_node_070::payment::PaymentDirection::Outbound, +// PRE_DOWNGRADE_PAYMENT_MSAT, +// ); +// assert_v070_bolt11_payment( +// &node_b_v070, +// &pre_downgrade_payment_id, +// ldk_node_070::payment::PaymentDirection::Inbound, +// PRE_DOWNGRADE_PAYMENT_MSAT, +// ); +// +// node_a_v070.sync_wallets().unwrap(); +// node_b_v070.sync_wallets().unwrap(); +// node_a_v070.connect(node_id_b, v070_addresses_b.first().unwrap().clone(), true).unwrap(); +// wait_for_v070_usable_channel(&node_a_v070, node_id_b).await; +// wait_for_v070_usable_channel(&node_b_v070, node_id_a).await; +// drain_v070_events(&node_a_v070).await; +// drain_v070_events(&node_b_v070).await; +// +// send_v070_bolt11_payment( +// &node_a_v070, +// &node_b_v070, +// POST_DOWNGRADE_PAYMENT_MSAT, +// "post-downgrade", +// ) +// .await; +// +// node_a_v070.stop().unwrap(); +// node_b_v070.stop().unwrap(); +// } +// +// fn build_current_node( +// storage_path: String, seed_bytes: [u8; 64], listening_addresses: Vec, +// alias: &str, esplora_url: &str, +// ) -> CurrentNode { +// let mut config = Config::default(); +// config.network = bitcoin::Network::Regtest; +// config.storage_dir_path = storage_path; +// config.listening_addresses = Some(listening_addresses); +// config.anchor_channels_config = None; +// +// // Use the v1 filesystem layout that v0.7.0's filesystem builder can reopen. +// let mut fs_store_path = PathBuf::from(&config.storage_dir_path); +// fs_store_path.push("fs_store"); +// #[allow(unused_mut)] +// let mut builder = ldk_node::Builder::from_config(config); +// builder.set_node_alias(alias.to_string()).unwrap(); +// +// let mut sync_config = EsploraSyncConfig::default(); +// sync_config.background_sync_config = None; +// builder.set_chain_source_esplora(esplora_url.to_owned(), Some(sync_config)); +// +// #[cfg(feature = "uniffi")] +// let node_entropy = std::sync::Arc::new(NodeEntropy::from_seed_bytes(seed_bytes.to_vec()).unwrap()); +// #[cfg(not(feature = "uniffi"))] +// let node_entropy = NodeEntropy::from_seed_bytes(seed_bytes); +// +// let kv_store = FilesystemStore::new(fs_store_path); +// let node = builder.build_with_store(node_entropy.into(), kv_store).unwrap(); +// node.start().unwrap(); +// node +// } +// +// fn build_v070_node( +// storage_path: String, seed_bytes: [u8; 64], +// listening_addresses: Vec, alias: &str, +// esplora_url: &str, +// ) -> ldk_node_070::Node { +// let mut builder = ldk_node_070::Builder::new(); +// builder.set_network(bitcoin::Network::Regtest); +// builder.set_storage_dir_path(storage_path); +// builder.set_entropy_seed_bytes(seed_bytes); +// builder.set_listening_addresses(listening_addresses).unwrap(); +// builder.set_node_alias(alias.to_string()).unwrap(); +// builder.set_chain_source_esplora(esplora_url.to_owned(), None); +// let node = builder.build_with_fs_store().unwrap(); +// node.start().unwrap(); +// node +// } +// +// async fn open_current_channel(node_a: &CurrentNode, node_b: &CurrentNode) -> bitcoin::OutPoint { +// node_a +// .open_channel( +// node_b.node_id(), +// node_b.listening_addresses().unwrap().first().unwrap().clone(), +// CHANNEL_AMOUNT_SAT, +// Some(PUSH_AMOUNT_MSAT), +// None, +// ) +// .unwrap(); +// +// let funding_txo_a = expect_current_channel_pending(node_a, node_b.node_id()).await; +// let funding_txo_b = expect_current_channel_pending(node_b, node_a.node_id()).await; +// assert_eq!(funding_txo_a, funding_txo_b); +// funding_txo_a +// } +// +// async fn send_current_bolt11_payment( +// payer: &CurrentNode, payee: &CurrentNode, amount_msat: u64, description: &str, +// ) -> ldk_node::lightning::ln::channelmanager::PaymentId { +// let invoice_description = CurrentBolt11InvoiceDescription::Direct( +// CurrentDescription::new(description.to_owned()).unwrap(), +// ); +// let invoice = payee +// .bolt11_payment() +// .receive(amount_msat, &invoice_description.clone().into(), 3600) +// .unwrap(); +// let payment_id = payer.bolt11_payment().send(&invoice, None).unwrap(); +// expect_current_payment_successful(payer, &payment_id).await; +// expect_current_payment_received(payee, amount_msat).await; +// assert_eq!( +// payer.payment(&payment_id).unwrap().status, +// ldk_node::payment::PaymentStatus::Succeeded +// ); +// payment_id +// } +// +// async fn send_v070_bolt11_payment( +// payer: &ldk_node_070::Node, payee: &ldk_node_070::Node, amount_msat: u64, description: &str, +// ) { +// let invoice_description = ldk_node_070::lightning_invoice::Bolt11InvoiceDescription::Direct( +// ldk_node_070::lightning_invoice::Description::new(description.to_owned()).unwrap(), +// ); +// let invoice = payee.bolt11_payment().receive(amount_msat, &invoice_description, 3600).unwrap(); +// let payment_id = payer.bolt11_payment().send(&invoice, None).unwrap(); +// expect_v070_payment_successful(payer, &payment_id).await; +// expect_v070_payment_received(payee, amount_msat).await; +// assert_eq!( +// payer.payment(&payment_id).unwrap().status, +// ldk_node_070::payment::PaymentStatus::Succeeded +// ); +// } +// +// async fn expect_current_channel_pending( +// node: &CurrentNode, expected_counterparty: PublicKey, +// ) -> bitcoin::OutPoint { +// match next_current_event(node).await { +// ldk_node::Event::ChannelPending { counterparty_node_id, funding_txo, .. } => { +// assert_eq!(counterparty_node_id, expected_counterparty); +// node.event_handled().unwrap(); +// funding_txo +// }, +// event => panic!("{} got unexpected event: {:?}", node.node_id(), event), +// } +// } +// +// async fn expect_current_channel_ready(node: &CurrentNode, expected_counterparty: PublicKey) { +// match next_current_event(node).await { +// ldk_node::Event::ChannelReady { counterparty_node_id, .. } => { +// assert_eq!(counterparty_node_id, Some(expected_counterparty)); +// node.event_handled().unwrap(); +// }, +// event => panic!("{} got unexpected event: {:?}", node.node_id(), event), +// } +// } +// +// async fn expect_current_payment_successful( +// node: &CurrentNode, expected_payment_id: &ldk_node::lightning::ln::channelmanager::PaymentId, +// ) { +// match next_current_event(node).await { +// ldk_node::Event::PaymentSuccessful { payment_id, .. } => { +// assert_eq!(payment_id.as_ref(), Some(expected_payment_id)); +// node.event_handled().unwrap(); +// }, +// event => panic!("{} got unexpected event: {:?}", node.node_id(), event), +// } +// } +// +// async fn expect_current_payment_received(node: &CurrentNode, expected_amount_msat: u64) { +// match next_current_event(node).await { +// ldk_node::Event::PaymentReceived { amount_msat, payment_id, .. } => { +// assert_eq!(amount_msat, expected_amount_msat); +// assert!(payment_id.is_some()); +// node.event_handled().unwrap(); +// }, +// event => panic!("{} got unexpected event: {:?}", node.node_id(), event), +// } +// } +// +// async fn expect_v070_payment_successful( +// node: &ldk_node_070::Node, +// expected_payment_id: &ldk_node_070::lightning::ln::channelmanager::PaymentId, +// ) { +// match next_v070_event(node).await { +// ldk_node_070::Event::PaymentSuccessful { payment_id, .. } => { +// assert_eq!(payment_id.as_ref(), Some(expected_payment_id)); +// node.event_handled().unwrap(); +// }, +// event => panic!("{} got unexpected event: {:?}", node.node_id(), event), +// } +// } +// +// async fn expect_v070_payment_received(node: &ldk_node_070::Node, expected_amount_msat: u64) { +// match next_v070_event(node).await { +// ldk_node_070::Event::PaymentReceived { amount_msat, payment_id, .. } => { +// assert_eq!(amount_msat, expected_amount_msat); +// assert!(payment_id.is_some()); +// node.event_handled().unwrap(); +// }, +// event => panic!("{} got unexpected event: {:?}", node.node_id(), event), +// } +// } +// +// async fn next_current_event(node: &CurrentNode) -> ldk_node::Event { +// tokio::time::timeout(Duration::from_secs(common::INTEROP_TIMEOUT_SECS), node.next_event_async()) +// .await +// .unwrap_or_else(|_| panic!("{} timed out waiting for event", node.node_id())) +// } +// +// async fn next_v070_event(node: &ldk_node_070::Node) -> ldk_node_070::Event { +// tokio::time::timeout(Duration::from_secs(common::INTEROP_TIMEOUT_SECS), node.next_event_async()) +// .await +// .unwrap_or_else(|_| panic!("{} timed out waiting for event", node.node_id())) +// } +// +// async fn drain_v070_events(node: &ldk_node_070::Node) { +// while tokio::time::timeout(Duration::from_millis(250), node.next_event_async()).await.is_ok() { +// node.event_handled().unwrap(); +// } +// } +// +// async fn wait_for_v070_usable_channel(node: &ldk_node_070::Node, counterparty_node_id: PublicKey) { +// for _ in 0..40 { +// let channels = node.list_channels(); +// if let Some(channel) = +// channels.iter().find(|c| c.counterparty_node_id == counterparty_node_id) +// { +// assert_eq!(channel.channel_value_sats, CHANNEL_AMOUNT_SAT); +// if channel.is_channel_ready && channel.is_usable { +// return; +// } +// } +// tokio::time::sleep(Duration::from_millis(250)).await; +// } +// +// panic!( +// "{} failed to restore a usable v0.7.0 channel with {}", +// node.node_id(), +// counterparty_node_id +// ); +// } +// +// fn assert_current_channel_ready(node: &CurrentNode, counterparty_node_id: PublicKey) { +// let channels = node.list_channels(); +// let channel = channels.iter().find(|c| c.counterparty_node_id == counterparty_node_id).unwrap(); +// assert_eq!(channel.channel_value_sats, CHANNEL_AMOUNT_SAT); +// assert!(channel.is_channel_ready); +// } +// +// fn assert_v070_bolt11_payment( +// node: &ldk_node_070::Node, payment_id: &ldk_node_070::lightning::ln::channelmanager::PaymentId, +// expected_direction: ldk_node_070::payment::PaymentDirection, expected_amount_msat: u64, +// ) { +// let payment = node.payment(payment_id).unwrap(); +// assert_eq!(payment.amount_msat, Some(expected_amount_msat)); +// assert_eq!(payment.direction, expected_direction); +// assert_eq!(payment.status, ldk_node_070::payment::PaymentStatus::Succeeded); +// assert!(matches!(payment.kind, ldk_node_070::payment::PaymentKind::Bolt11 { .. })); +// } +// +// fn to_v070_socket_addresses( +// addresses: &[CurrentSocketAddress], +// ) -> Vec { +// addresses +// .iter() +// .map(|address| match address { +// CurrentSocketAddress::TcpIpV4 { addr, port } => { +// ldk_node_070::lightning::ln::msgs::SocketAddress::TcpIpV4 { +// addr: *addr, +// port: *port, +// } +// }, +// _ => panic!("unexpected non-IPv4 test address: {:?}", address), +// }) +// .collect() +// }