@@ -65,7 +65,9 @@ use bitcoin::secp256k1::PublicKey;
6565use bitcoin:: { BlockHash , Network } ;
6666
6767#[ cfg( any( vss, vss_test) ) ]
68- use bitcoin:: bip32:: ChildNumber ;
68+ use bitcoin:: bip32:: { ChildNumber , Xpriv } ;
69+ #[ cfg( any( vss, vss_test) ) ]
70+ use std:: collections:: HashMap ;
6971use std:: convert:: TryInto ;
7072use std:: default:: Default ;
7173use std:: fmt;
@@ -74,6 +76,8 @@ use std::path::PathBuf;
7476use std:: sync:: atomic:: AtomicBool ;
7577use std:: sync:: { Arc , Mutex , RwLock } ;
7678use std:: time:: SystemTime ;
79+ #[ cfg( any( vss, vss_test) ) ]
80+ use vss_client:: headers:: { FixedHeaders , LnurlAuthToJwtProvider , VssHeaderProvider } ;
7781
7882#[ derive( Debug , Clone ) ]
7983enum ChainDataSourceConfig {
@@ -368,10 +372,28 @@ impl NodeBuilder {
368372 self . build_with_store ( kv_store)
369373 }
370374
371- /// Builds a [`Node`] instance with a [`VssStore` ] backend and according to the options
375+ /// Builds a [`Node`] instance with a [VSS ] backend and according to the options
372376 /// previously configured.
377+ ///
378+ /// Uses [LNURL-auth] based authentication scheme as default method for authentication/authorization.
379+ ///
380+ /// The LNURL challenge will be retrieved by making a request to the given `lnurl_auth_server_url`.
381+ /// The returned JWT token in response to the signed LNURL request, will be used for
382+ /// authentication/authorization of all the requests made to VSS.
383+ ///
384+ /// `fixed_headers` are included as it is in all the requests made to VSS and LNURL auth server.
385+ ///
386+ /// **Caution**: VSS support is in **alpha** and is considered experimental.
387+ /// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
388+ /// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
389+ ///
390+ /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
391+ /// [LNURL-auth]: https://github.com/lnurl/luds/blob/luds/04.md
373392 #[ cfg( any( vss, vss_test) ) ]
374- pub fn build_with_vss_store ( & self , url : String , store_id : String ) -> Result < Node , BuildError > {
393+ pub fn build_with_vss_store (
394+ & self , vss_url : String , store_id : String , lnurl_auth_server_url : String ,
395+ fixed_headers : HashMap < String , String > ,
396+ ) -> Result < Node , BuildError > {
375397 use bitcoin:: key:: Secp256k1 ;
376398
377399 let logger = setup_logger ( & self . config ) ?;
@@ -381,23 +403,81 @@ impl NodeBuilder {
381403 self . entropy_source_config . as_ref ( ) ,
382404 Arc :: clone ( & logger) ,
383405 ) ?;
406+
384407 let config = Arc :: new ( self . config . clone ( ) ) ;
385408
386- let xprv = bitcoin:: bip32:: Xpriv :: new_master ( config. network , & seed_bytes) . map_err ( |e| {
387- log_error ! ( logger, "Failed to derive master secret: {}" , e) ;
388- BuildError :: InvalidSeedBytes
389- } ) ?;
409+ let vss_xprv = derive_vss_xprv ( config, & seed_bytes, Arc :: clone ( & logger) ) ?;
390410
391- let vss_xprv = xprv
392- . derive_priv ( & Secp256k1 :: new ( ) , & [ ChildNumber :: Hardened { index : 877 } ] )
411+ let lnurl_auth_xprv = vss_xprv
412+ . derive_priv ( & Secp256k1 :: new ( ) , & [ ChildNumber :: Hardened { index : 138 } ] )
393413 . map_err ( |e| {
394414 log_error ! ( logger, "Failed to derive VSS secret: {}" , e) ;
395415 BuildError :: KVStoreSetupFailed
396416 } ) ?;
397417
418+ let lnurl_auth_jwt_provider =
419+ LnurlAuthToJwtProvider :: new ( lnurl_auth_xprv, lnurl_auth_server_url, fixed_headers)
420+ . map_err ( |e| {
421+ log_error ! ( logger, "Failed to create LnurlAuthToJwtProvider: {}" , e) ;
422+ BuildError :: KVStoreSetupFailed
423+ } ) ?;
424+
425+ let header_provider = Arc :: new ( lnurl_auth_jwt_provider) ;
426+
427+ self . build_with_vss_store_and_header_provider ( vss_url, store_id, header_provider)
428+ }
429+
430+ /// Builds a [`Node`] instance with a [VSS] backend and according to the options
431+ /// previously configured.
432+ ///
433+ /// Uses [`FixedHeaders`] as default method for authentication/authorization.
434+ ///
435+ /// Given `fixed_headers` are included as it is in all the requests made to VSS.
436+ ///
437+ /// **Caution**: VSS support is in **alpha** and is considered experimental.
438+ /// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
439+ /// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
440+ ///
441+ /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
442+ #[ cfg( any( vss, vss_test) ) ]
443+ pub fn build_with_vss_store_and_fixed_headers (
444+ & self , vss_url : String , store_id : String , fixed_headers : HashMap < String , String > ,
445+ ) -> Result < Node , BuildError > {
446+ let header_provider = Arc :: new ( FixedHeaders :: new ( fixed_headers) ) ;
447+
448+ self . build_with_vss_store_and_header_provider ( vss_url, store_id, header_provider)
449+ }
450+
451+ /// Builds a [`Node`] instance with a [VSS] backend and according to the options
452+ /// previously configured.
453+ ///
454+ /// Given `header_provider` is used to attach headers to every request made
455+ /// to VSS.
456+ ///
457+ /// **Caution**: VSS support is in **alpha** and is considered experimental.
458+ /// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
459+ /// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
460+ ///
461+ /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
462+ #[ cfg( any( vss, vss_test) ) ]
463+ pub fn build_with_vss_store_and_header_provider (
464+ & self , vss_url : String , store_id : String , header_provider : Arc < dyn VssHeaderProvider > ,
465+ ) -> Result < Node , BuildError > {
466+ let logger = setup_logger ( & self . config ) ?;
467+
468+ let seed_bytes = seed_bytes_from_config (
469+ & self . config ,
470+ self . entropy_source_config . as_ref ( ) ,
471+ Arc :: clone ( & logger) ,
472+ ) ?;
473+
474+ let config = Arc :: new ( self . config . clone ( ) ) ;
475+
476+ let vss_xprv = derive_vss_xprv ( config. clone ( ) , & seed_bytes, Arc :: clone ( & logger) ) ?;
477+
398478 let vss_seed_bytes: [ u8 ; 32 ] = vss_xprv. private_key . secret_bytes ( ) ;
399479
400- let vss_store = Arc :: new ( VssStore :: new ( url , store_id, vss_seed_bytes) ) ;
480+ let vss_store = Arc :: new ( VssStore :: new ( vss_url , store_id, vss_seed_bytes, header_provider ) ) ;
401481 build_with_store_internal (
402482 config,
403483 self . chain_data_source_config . as_ref ( ) ,
@@ -575,6 +655,80 @@ impl ArcedNodeBuilder {
575655 self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) . map ( Arc :: new)
576656 }
577657
658+ /// Builds a [`Node`] instance with a [VSS] backend and according to the options
659+ /// previously configured.
660+ ///
661+ /// Uses [LNURL-auth] based authentication scheme as default method for authentication/authorization.
662+ ///
663+ /// The LNURL challenge will be retrieved by making a request to the given `lnurl_auth_server_url`.
664+ /// The returned JWT token in response to the signed LNURL request, will be used for
665+ /// authentication/authorization of all the requests made to VSS.
666+ ///
667+ /// `fixed_headers` are included as it is in all the requests made to VSS and LNURL auth server.
668+ ///
669+ /// **Caution**: VSS support is in **alpha** and is considered experimental.
670+ /// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
671+ /// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
672+ ///
673+ /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
674+ /// [LNURL-auth]: https://github.com/lnurl/luds/blob/luds/04.md
675+ #[ cfg( any( vss, vss_test) ) ]
676+ pub fn build_with_vss_store (
677+ & self , vss_url : String , store_id : String , lnurl_auth_server_url : String ,
678+ fixed_headers : HashMap < String , String > ,
679+ ) -> Result < Arc < Node > , BuildError > {
680+ self . inner
681+ . read ( )
682+ . unwrap ( )
683+ . build_with_vss_store ( vss_url, store_id, lnurl_auth_server_url, fixed_headers)
684+ . map ( Arc :: new)
685+ }
686+
687+ /// Builds a [`Node`] instance with a [VSS] backend and according to the options
688+ /// previously configured.
689+ ///
690+ /// Uses [`FixedHeaders`] as default method for authentication/authorization.
691+ ///
692+ /// Given `fixed_headers` are included as it is in all the requests made to VSS.
693+ ///
694+ /// **Caution**: VSS support is in **alpha** and is considered experimental.
695+ /// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
696+ /// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
697+ ///
698+ /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
699+ #[ cfg( any( vss, vss_test) ) ]
700+ pub fn build_with_vss_store_and_fixed_headers (
701+ & self , vss_url : String , store_id : String , fixed_headers : HashMap < String , String > ,
702+ ) -> Result < Arc < Node > , BuildError > {
703+ self . inner
704+ . read ( )
705+ . unwrap ( )
706+ . build_with_vss_store_and_fixed_headers ( vss_url, store_id, fixed_headers)
707+ . map ( Arc :: new)
708+ }
709+
710+ /// Builds a [`Node`] instance with a [VSS] backend and according to the options
711+ /// previously configured.
712+ ///
713+ /// Given `header_provider` is used to attach headers to every request made
714+ /// to VSS.
715+ ///
716+ /// **Caution**: VSS support is in **alpha** and is considered experimental.
717+ /// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
718+ /// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
719+ ///
720+ /// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
721+ #[ cfg( any( vss, vss_test) ) ]
722+ pub fn build_with_vss_store_and_header_provider (
723+ & self , vss_url : String , store_id : String , header_provider : Arc < dyn VssHeaderProvider > ,
724+ ) -> Result < Arc < Node > , BuildError > {
725+ self . inner
726+ . read ( )
727+ . unwrap ( )
728+ . build_with_vss_store_and_header_provider ( vss_url, store_id, header_provider)
729+ . map ( Arc :: new)
730+ }
731+
578732 /// Builds a [`Node`] instance according to the options previously configured.
579733 pub fn build_with_store ( & self , kv_store : Arc < DynStore > ) -> Result < Arc < Node > , BuildError > {
580734 self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) . map ( Arc :: new)
@@ -1118,6 +1272,23 @@ fn seed_bytes_from_config(
11181272 }
11191273}
11201274
1275+ #[ cfg( any( vss, vss_test) ) ]
1276+ fn derive_vss_xprv (
1277+ config : Arc < Config > , seed_bytes : & [ u8 ; 64 ] , logger : Arc < FilesystemLogger > ,
1278+ ) -> Result < Xpriv , BuildError > {
1279+ use bitcoin:: key:: Secp256k1 ;
1280+
1281+ let xprv = Xpriv :: new_master ( config. network , seed_bytes) . map_err ( |e| {
1282+ log_error ! ( logger, "Failed to derive master secret: {}" , e) ;
1283+ BuildError :: InvalidSeedBytes
1284+ } ) ?;
1285+
1286+ xprv. derive_priv ( & Secp256k1 :: new ( ) , & [ ChildNumber :: Hardened { index : 877 } ] ) . map_err ( |e| {
1287+ log_error ! ( logger, "Failed to derive VSS secret: {}" , e) ;
1288+ BuildError :: KVStoreSetupFailed
1289+ } )
1290+ }
1291+
11211292/// Sanitize the user-provided node alias to ensure that it is a valid protocol-specified UTF-8 string.
11221293pub ( crate ) fn sanitize_alias ( alias_str : & str ) -> Result < NodeAlias , BuildError > {
11231294 let alias = alias_str. trim ( ) ;
0 commit comments