@@ -39,7 +39,7 @@ use ldk_node::config::{
3939 AsyncPaymentsRole , EsploraSyncConfig , ADDRESS_POOL_SIZE , DEFAULT_FULL_SCAN_STOP_GAP ,
4040} ;
4141use ldk_node:: entropy:: NodeEntropy ;
42- #[ cfg( all ( not ( feature = "uniffi" ) , feature = " storage-tier") ) ]
42+ #[ cfg( feature = "storage-tier" ) ]
4343use ldk_node:: io:: sqlite_store:: SqliteStore ;
4444use ldk_node:: liquidity:: LSPS2ServiceConfig ;
4545use ldk_node:: payment:: {
@@ -53,6 +53,12 @@ use lightning::routing::router::RouteParametersConfig;
5353#[ cfg( feature = "storage-tier" ) ]
5454use lightning:: util:: persist:: MigratableKVStore ;
5555use 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+ } ;
5662use lightning_invoice:: { Bolt11InvoiceDescription , Description } ;
5763use lightning_types:: payment:: { PaymentHash , PaymentPreimage } ;
5864use 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