@@ -65,7 +65,9 @@ use bitcoin::secp256k1::PublicKey;
65
65
use bitcoin:: { BlockHash , Network } ;
66
66
67
67
#[ 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 ;
69
71
use std:: convert:: TryInto ;
70
72
use std:: default:: Default ;
71
73
use std:: fmt;
@@ -74,6 +76,8 @@ use std::path::PathBuf;
74
76
use std:: sync:: atomic:: AtomicBool ;
75
77
use std:: sync:: { Arc , Mutex , RwLock } ;
76
78
use std:: time:: SystemTime ;
79
+ #[ cfg( any( vss, vss_test) ) ]
80
+ use vss_client:: headers:: { FixedHeaders , LnurlAuthToJwtProvider , VssHeaderProvider } ;
77
81
78
82
#[ derive( Debug , Clone ) ]
79
83
enum ChainDataSourceConfig {
@@ -368,10 +372,28 @@ impl NodeBuilder {
368
372
self . build_with_store ( kv_store)
369
373
}
370
374
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
372
376
/// 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
373
392
#[ 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 > {
375
397
use bitcoin:: key:: Secp256k1 ;
376
398
377
399
let logger = setup_logger ( & self . config ) ?;
@@ -381,23 +403,81 @@ impl NodeBuilder {
381
403
self . entropy_source_config . as_ref ( ) ,
382
404
Arc :: clone ( & logger) ,
383
405
) ?;
406
+
384
407
let config = Arc :: new ( self . config . clone ( ) ) ;
385
408
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) ) ?;
390
410
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 } ] )
393
413
. map_err ( |e| {
394
414
log_error ! ( logger, "Failed to derive VSS secret: {}" , e) ;
395
415
BuildError :: KVStoreSetupFailed
396
416
} ) ?;
397
417
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
+
398
478
let vss_seed_bytes: [ u8 ; 32 ] = vss_xprv. private_key . secret_bytes ( ) ;
399
479
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 ) ) ;
401
481
build_with_store_internal (
402
482
config,
403
483
self . chain_data_source_config . as_ref ( ) ,
@@ -575,6 +655,80 @@ impl ArcedNodeBuilder {
575
655
self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) . map ( Arc :: new)
576
656
}
577
657
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
+
578
732
/// Builds a [`Node`] instance according to the options previously configured.
579
733
pub fn build_with_store ( & self , kv_store : Arc < DynStore > ) -> Result < Arc < Node > , BuildError > {
580
734
self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) . map ( Arc :: new)
@@ -1118,6 +1272,23 @@ fn seed_bytes_from_config(
1118
1272
}
1119
1273
}
1120
1274
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
+
1121
1292
/// Sanitize the user-provided node alias to ensure that it is a valid protocol-specified UTF-8 string.
1122
1293
pub ( crate ) fn sanitize_alias ( alias_str : & str ) -> Result < NodeAlias , BuildError > {
1123
1294
let alias = alias_str. trim ( ) ;
0 commit comments