@@ -24,7 +24,9 @@ use bitcoin::Network;
2424use lightning:: impl_writeable_tlv_based_enum;
2525use lightning:: io:: { self , Error , ErrorKind } ;
2626use lightning:: sign:: { EntropySource as LdkEntropySource , RandomBytes } ;
27- use lightning:: util:: persist:: { KVStore , PageToken , PaginatedKVStore , PaginatedListResponse } ;
27+ use lightning:: util:: persist:: {
28+ KVStore , MigratableKVStore , PageToken , PaginatedKVStore , PaginatedListResponse ,
29+ } ;
2830use lightning:: util:: ser:: { Readable , Writeable } ;
2931use prost:: Message ;
3032use vss_client:: client:: VssClient ;
@@ -321,6 +323,22 @@ impl PaginatedKVStore for VssStore {
321323 }
322324}
323325
326+ impl MigratableKVStore for VssStore {
327+ fn list_all_keys (
328+ & self ,
329+ ) -> impl Future < Output = Result < Vec < ( String , String , String ) > , io:: Error > > + ' static + Send {
330+ let inner = Arc :: clone ( & self . inner ) ;
331+ let runtime = self . internal_runtime ( ) ;
332+ async move {
333+ let task = runtime
334+ . spawn ( async move { inner. list_all_keys_internal ( & inner. async_client ) . await } ) ;
335+ task. await . map_err ( |e| {
336+ io:: Error :: new ( io:: ErrorKind :: Other , format ! ( "VSS runtime task failed: {}" , e) )
337+ } ) ?
338+ }
339+ }
340+ }
341+
324342impl Drop for VssStore {
325343 fn drop ( & mut self ) {
326344 if let Some ( runtime) = self . internal_runtime . take ( ) {
@@ -422,6 +440,41 @@ impl VssStoreInner {
422440 Ok ( actual_key)
423441 }
424442
443+ fn extract_namespaces ( & self , unified_key : & str ) -> io:: Result < ( String , String ) > {
444+ if self . schema_version == VssSchemaVersion :: V1 {
445+ let mut parts = unified_key. splitn ( 2 , '#' ) ;
446+ let obfuscated_namespace = parts. next ( ) ;
447+ let _obfuscated_key = parts. next ( ) ;
448+ match ( obfuscated_namespace, _obfuscated_key) {
449+ ( Some ( obfuscated_namespace) , Some ( _obfuscated_key) ) => {
450+ let namespace = self . key_obfuscator . deobfuscate ( obfuscated_namespace) ?;
451+ let mut namespace_parts = namespace. splitn ( 2 , '#' ) ;
452+ let primary_namespace = namespace_parts. next ( ) ;
453+ let secondary_namespace = namespace_parts. next ( ) ;
454+ match ( primary_namespace, secondary_namespace) {
455+ ( Some ( primary_namespace) , Some ( secondary_namespace) ) => {
456+ Ok ( ( primary_namespace. to_string ( ) , secondary_namespace. to_string ( ) ) )
457+ } ,
458+ _ => Err ( Error :: new ( ErrorKind :: InvalidData , "Invalid namespace format" ) ) ,
459+ }
460+ } ,
461+ _ => Err ( Error :: new ( ErrorKind :: InvalidData , "Invalid key format" ) ) ,
462+ }
463+ } else {
464+ // Default to V0 schema.
465+ let mut parts = unified_key. splitn ( 3 , '#' ) ;
466+ let primary_namespace = parts. next ( ) ;
467+ let secondary_namespace = parts. next ( ) ;
468+ match ( primary_namespace, secondary_namespace) {
469+ ( Some ( _obfuscated_key) , None ) => Ok ( ( "" . to_string ( ) , "" . to_string ( ) ) ) ,
470+ ( Some ( primary_namespace) , Some ( secondary_namespace) ) => {
471+ Ok ( ( primary_namespace. to_string ( ) , secondary_namespace. to_string ( ) ) )
472+ } ,
473+ _ => Err ( Error :: new ( ErrorKind :: InvalidData , "Invalid key format" ) ) ,
474+ }
475+ }
476+ }
477+
425478 async fn list_keys (
426479 & self , client : & VssClient < CustomRetryPolicy > , primary_namespace : & str ,
427480 secondary_namespace : & str , key_prefix : String , page_token : Option < String > ,
@@ -625,6 +678,52 @@ impl VssStoreInner {
625678 Ok ( PaginatedListResponse { keys, next_page_token } )
626679 }
627680
681+ async fn list_all_keys_internal (
682+ & self , client : & VssClient < CustomRetryPolicy > ,
683+ ) -> io:: Result < Vec < ( String , String , String ) > > {
684+ let mut page_token: Option < String > = None ;
685+ let mut keys = vec ! [ ] ;
686+ loop {
687+ let request = ListKeyVersionsRequest {
688+ store_id : self . store_id . clone ( ) ,
689+ key_prefix : None ,
690+ page_token,
691+ page_size : Some ( PAGE_SIZE ) ,
692+ } ;
693+
694+ let response = client. list_key_versions ( & request) . await . map_err ( |e| {
695+ let msg = format ! ( "Failed to list all keys: {}" , e) ;
696+ Error :: new ( ErrorKind :: Other , msg)
697+ } ) ?;
698+
699+ for kv in response. key_versions {
700+ let ( primary_namespace, secondary_namespace) = self . extract_namespaces ( & kv. key ) ?;
701+ let key = match self . extract_key ( & kv. key ) {
702+ Ok ( key) => key,
703+ Err ( _)
704+ if self . schema_version == VssSchemaVersion :: V0 && !kv. key . contains ( '#' ) =>
705+ {
706+ self . key_obfuscator . deobfuscate ( & kv. key ) ?
707+ } ,
708+ Err ( e) => return Err ( e) ,
709+ } ;
710+ if primary_namespace. is_empty ( )
711+ && secondary_namespace. is_empty ( )
712+ && key == VSS_SCHEMA_VERSION_KEY
713+ {
714+ continue ;
715+ }
716+ keys. push ( ( primary_namespace, secondary_namespace, key) ) ;
717+ }
718+
719+ match response. next_page_token . filter ( |t| !t. is_empty ( ) ) {
720+ Some ( t) => page_token = Some ( t) ,
721+ None => break ,
722+ }
723+ }
724+ Ok ( keys)
725+ }
726+
628727 async fn execute_locked_write <
629728 F : Future < Output = Result < ( ) , lightning:: io:: Error > > ,
630729 FN : FnOnce ( ) -> F ,
@@ -1041,6 +1140,27 @@ mod tests {
10411140 drop ( vss_store)
10421141 }
10431142
1143+ #[ tokio:: test]
1144+ async fn vss_list_all_keys ( ) {
1145+ let store = build_vss_store ( ) ;
1146+
1147+ KVStore :: write ( & store, "ns_a" , "sub_a" , "key_a" , vec ! [ 1u8 ] ) . await . unwrap ( ) ;
1148+ KVStore :: write ( & store, "ns_a" , "sub_b" , "key_b" , vec ! [ 2u8 ] ) . await . unwrap ( ) ;
1149+ KVStore :: write ( & store, "ns_b" , "" , "key_c" , vec ! [ 3u8 ] ) . await . unwrap ( ) ;
1150+
1151+ let mut keys = MigratableKVStore :: list_all_keys ( & store) . await . unwrap ( ) ;
1152+ keys. sort ( ) ;
1153+
1154+ assert_eq ! (
1155+ keys,
1156+ vec![
1157+ ( "ns_a" . to_string( ) , "sub_a" . to_string( ) , "key_a" . to_string( ) ) ,
1158+ ( "ns_a" . to_string( ) , "sub_b" . to_string( ) , "key_b" . to_string( ) ) ,
1159+ ( "ns_b" . to_string( ) , "" . to_string( ) , "key_c" . to_string( ) ) ,
1160+ ]
1161+ ) ;
1162+ }
1163+
10441164 #[ tokio:: test]
10451165 async fn vss_paginated_listing ( ) {
10461166 let store = build_vss_store ( ) ;
0 commit comments