Skip to content

Commit 07f5134

Browse files
committed
Test tiered storage across a full node lifecycle
We expand the existing backup integration test to configure a custom primary store alongside separate SQLite backup and ephemeral stores, and use the shared builder-store adapter so the test covers both native and UniFFI-enabled builds. We seed the primary store before node construction and verify that the builder enumerates its keys and backfills the empty backup. We run a complete channel lifecycle to produce representative durable and rebuildable state. After shutdown, we verify that wallet, channel manager, and payment data is mirrored across the primary and backup stores and excluded from ephemeral storage. Also, we verify conversely that network graph data is routed only to the ephemeral store. Assisted-by: Amp (AI coding agent)
1 parent d588704 commit 07f5134

1 file changed

Lines changed: 113 additions & 17 deletions

File tree

tests/integration_tests_rust.rs

Lines changed: 113 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use ldk_node::config::{
3939
AsyncPaymentsRole, EsploraSyncConfig, ADDRESS_POOL_SIZE, DEFAULT_FULL_SCAN_STOP_GAP,
4040
};
4141
use ldk_node::entropy::NodeEntropy;
42-
#[cfg(all(not(feature = "uniffi"), feature = "storage-tier"))]
42+
#[cfg(feature = "storage-tier")]
4343
use ldk_node::io::sqlite_store::SqliteStore;
4444
use ldk_node::liquidity::LSPS2ServiceConfig;
4545
use ldk_node::payment::{
@@ -53,6 +53,12 @@ use lightning::routing::router::RouteParametersConfig;
5353
#[cfg(feature = "storage-tier")]
5454
use lightning::util::persist::MigratableKVStore;
5555
use lightning::util::persist::{KVStore, PageToken, PaginatedKVStore, PaginatedListResponse};
56+
#[cfg(feature = "storage-tier")]
57+
use lightning::util::persist::{
58+
CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
59+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, NETWORK_GRAPH_PERSISTENCE_KEY,
60+
NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE,
61+
};
5662
use lightning_invoice::{Bolt11InvoiceDescription, Description};
5763
use lightning_types::payment::{PaymentHash, PaymentPreimage};
5864
use log::LevelFilter;
@@ -4974,29 +4980,35 @@ async fn do_lsps2_multi_lsp_picks_cheapest(reverse_order: bool) {
49744980
cheap.stop().unwrap();
49754981
expensive.stop().unwrap();
49764982
}
4977-
4978-
// Builder backup-store configuration is not yet exposed via FFI (see #871)
4979-
#[cfg(all(not(feature = "uniffi"), feature = "storage-tier"))]
4983+
#[cfg(feature = "storage-tier")]
49804984
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
4981-
async fn builder_configures_sqlite_backup_store() {
4985+
async fn builder_routes_data_across_configured_storage_tiers() {
49824986
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
49834987
let chain_source = random_chain_source(&bitcoind, &electrsd);
49844988

4985-
let mut config_a = random_config();
4986-
config_a.store_type = TestStoreType::Sqlite;
4987-
let primary_dir = config_a.node_config.storage_dir_path.clone();
4989+
let config_a = random_config();
4990+
let primary_store = TestSyncStore::new(common::random_storage_path());
4991+
let preexisting_key = ("test", "", "preexisting");
4992+
let preexisting_value = vec![42];
4993+
primary_store
4994+
.write(preexisting_key.0, preexisting_key.1, preexisting_key.2, preexisting_value.clone())
4995+
.await
4996+
.unwrap();
49884997
let backup_dir = common::random_storage_path();
4998+
let ephemeral_dir = common::random_storage_path();
49894999

4990-
// Build node_a with backup storage configured
49915000
setup_builder!(builder_a, config_a.node_config.clone());
49925001
builder_a.set_chain_source_esplora(
49935002
format!("http://{}", electrsd.esplora_url.as_ref().unwrap()),
49945003
None,
49955004
);
49965005
builder_a.set_filesystem_logger(None, None);
49975006
builder_a.set_backup_storage_dir_path(backup_dir.to_str().unwrap().to_owned());
5007+
builder_a.set_ephemeral_storage_dir_path(ephemeral_dir.to_str().unwrap().to_owned());
49985008

4999-
let node_a = builder_a.build(config_a.node_entropy.into()).unwrap();
5009+
let node_a = builder_a
5010+
.build_with_store(config_a.node_entropy.into(), into_builder_store(primary_store.clone()))
5011+
.unwrap();
50005012
node_a.start().unwrap();
50015013
assert!(node_a.status().is_running);
50025014
assert!(node_a.status().latest_fee_rate_cache_update_timestamp.is_some());
@@ -5017,19 +5029,30 @@ async fn builder_configures_sqlite_backup_store() {
50175029
)
50185030
.await;
50195031

5020-
let primary_store = SqliteStore::new(
5021-
primary_dir.into(),
5022-
Some(ldk_node::io::sqlite_store::SQLITE_DB_FILE_NAME.to_string()),
5023-
Some(ldk_node::io::sqlite_store::KV_TABLE_NAME.to_string()),
5024-
)
5025-
.unwrap();
5026-
50275032
let backup_store = SqliteStore::new(
50285033
backup_dir,
50295034
Some(ldk_node::io::sqlite_store::SQLITE_BACKUP_DB_FILE_NAME.to_string()),
50305035
Some(ldk_node::io::sqlite_store::KV_TABLE_NAME.to_string()),
50315036
)
50325037
.unwrap();
5038+
let ephemeral_store = SqliteStore::new(
5039+
ephemeral_dir,
5040+
Some(ldk_node::io::sqlite_store::SQLITE_EPHEMERAL_DB_FILE_NAME.to_string()),
5041+
Some(ldk_node::io::sqlite_store::KV_TABLE_NAME.to_string()),
5042+
)
5043+
.unwrap();
5044+
5045+
assert_eq!(
5046+
backup_store.read(preexisting_key.0, preexisting_key.1, preexisting_key.2).await.unwrap(),
5047+
preexisting_value
5048+
);
5049+
assert!(
5050+
ephemeral_store
5051+
.read(preexisting_key.0, preexisting_key.1, preexisting_key.2)
5052+
.await
5053+
.is_err(),
5054+
"ephemeral store contains pre-existing durable data"
5055+
);
50335056

50345057
for (pn, sn, key) in [
50355058
("bdk_wallet", "", "descriptor"),
@@ -5043,5 +5066,78 @@ async fn builder_configures_sqlite_backup_store() {
50435066
let backup = backup_store.read(pn, sn, key).await.unwrap();
50445067

50455068
assert_eq!(backup, primary, "backup mismatch for {pn}/{sn}/{key}");
5069+
assert!(
5070+
ephemeral_store.read(pn, sn, key).await.is_err(),
5071+
"ephemeral store contains durable value {pn}/{sn}/{key}"
5072+
);
50465073
}
5074+
5075+
let primary_channel_manager = primary_store
5076+
.read(
5077+
CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
5078+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
5079+
CHANNEL_MANAGER_PERSISTENCE_KEY,
5080+
)
5081+
.await
5082+
.unwrap();
5083+
let backup_channel_manager = backup_store
5084+
.read(
5085+
CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
5086+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
5087+
CHANNEL_MANAGER_PERSISTENCE_KEY,
5088+
)
5089+
.await
5090+
.unwrap();
5091+
assert_eq!(backup_channel_manager, primary_channel_manager);
5092+
assert!(
5093+
ephemeral_store
5094+
.read(
5095+
CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
5096+
CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE,
5097+
CHANNEL_MANAGER_PERSISTENCE_KEY,
5098+
)
5099+
.await
5100+
.is_err(),
5101+
"ephemeral store contains channel manager data"
5102+
);
5103+
5104+
let mut primary_payments = primary_store.list("payments", "").await.unwrap();
5105+
let mut backup_payments = backup_store.list("payments", "").await.unwrap();
5106+
assert!(!primary_payments.is_empty());
5107+
primary_payments.sort();
5108+
backup_payments.sort();
5109+
assert_eq!(backup_payments, primary_payments);
5110+
assert!(ephemeral_store.list("payments", "").await.unwrap().is_empty());
5111+
5112+
let ephemeral_network_graph = ephemeral_store
5113+
.read(
5114+
NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE,
5115+
NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE,
5116+
NETWORK_GRAPH_PERSISTENCE_KEY,
5117+
)
5118+
.await
5119+
.expect("ephemeral store should contain network graph data");
5120+
assert!(!ephemeral_network_graph.is_empty());
5121+
assert!(
5122+
primary_store
5123+
.read(
5124+
NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE,
5125+
NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE,
5126+
NETWORK_GRAPH_PERSISTENCE_KEY,
5127+
)
5128+
.await
5129+
.is_err(),
5130+
"primary store contains ephemeral network graph data"
5131+
);
5132+
assert!(
5133+
backup_store
5134+
.read(
5135+
NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE,
5136+
NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE,
5137+
NETWORK_GRAPH_PERSISTENCE_KEY,
5138+
)
5139+
.await
5140+
.is_err(),
5141+
"backup store contains ephemeral network graph data"
5142+
);
50475143
}

0 commit comments

Comments
 (0)