@@ -46,7 +46,7 @@ use lightning::routing::scoring::{
4646use lightning:: sign:: EntropySource ;
4747
4848use lightning:: util:: persist:: {
49- read_channel_monitors, CHANNEL_MANAGER_PERSISTENCE_KEY ,
49+ read_channel_monitors, KVStore , CHANNEL_MANAGER_PERSISTENCE_KEY ,
5050 CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE , CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE ,
5151} ;
5252use lightning:: util:: ser:: ReadableArgs ;
@@ -579,6 +579,148 @@ impl NodeBuilder {
579579 }
580580}
581581
582+ #[ derive( Debug ) ]
583+ pub struct KVStoreBuilder {
584+ config : Config ,
585+ entropy_source_config : Option < EntropySourceConfig > ,
586+ log_writer_config : Option < LogWriterConfig > ,
587+ }
588+
589+ impl KVStoreBuilder {
590+ /// Creates a new builder instance with the default configuration.
591+ pub fn new ( ) -> Self {
592+ let config = Config :: default ( ) ;
593+ Self :: from_config ( config)
594+ }
595+
596+ /// Creates a new builder instance from an [`Config`].
597+ pub fn from_config ( config : Config ) -> Self {
598+ let entropy_source_config = None ;
599+ let log_writer_config = None ;
600+ Self { config, entropy_source_config, log_writer_config }
601+ }
602+
603+ //TODO: I think these methods should be extracted out to EntropySourceConfigBuilder. Both NodeBuilder
604+ // and KVStoreBuilder can directly take EntropySourceConfig as arg.
605+ /// Configures the builder instance to source its entropy from a seed file on disk.
606+ ///
607+ /// If the given file does not exist a new random seed file will be generated and
608+ /// stored at the given location.
609+ pub fn set_entropy_seed_path ( & mut self , seed_path : String ) -> & mut Self {
610+ self . entropy_source_config = Some ( EntropySourceConfig :: SeedFile ( seed_path) ) ;
611+ self
612+ }
613+
614+ /// Configures the builder instance to source its entropy from the given 64 seed bytes.
615+ pub fn set_entropy_seed_bytes ( & mut self , seed_bytes : Vec < u8 > ) -> Result < & mut Self , BuildError > {
616+ if seed_bytes. len ( ) != WALLET_KEYS_SEED_LEN {
617+ return Err ( BuildError :: InvalidSeedBytes ) ;
618+ }
619+ let mut bytes = [ 0u8 ; WALLET_KEYS_SEED_LEN ] ;
620+ bytes. copy_from_slice ( & seed_bytes) ;
621+ self . entropy_source_config = Some ( EntropySourceConfig :: SeedBytes ( bytes) ) ;
622+ Ok ( self )
623+ }
624+
625+ /// Configures the builder instance to source its entropy from a [BIP 39] mnemonic.
626+ ///
627+ /// [BIP 39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
628+ pub fn set_entropy_bip39_mnemonic (
629+ & mut self , mnemonic : Mnemonic , passphrase : Option < String > ,
630+ ) -> & mut Self {
631+ self . entropy_source_config =
632+ Some ( EntropySourceConfig :: Bip39Mnemonic { mnemonic, passphrase } ) ;
633+ self
634+ }
635+
636+ //TODO: Once we have KVStoreBuilder, we can have NodeBuilder directly take Arc<dyn KVStore> as arg.
637+ /// Builds a [`VssStore`] backend based implementation of [`KVStore`].
638+ pub fn build_vss_store (
639+ & self , vss_url : String , store_id : String , lnurl_auth_server_url : String ,
640+ fixed_headers : HashMap < String , String > ,
641+ ) -> Result < VssStore , BuildError > {
642+ use bitcoin:: key:: Secp256k1 ;
643+
644+ let logger = setup_logger ( & self . log_writer_config , & self . config ) ?;
645+
646+ let seed_bytes = seed_bytes_from_config (
647+ & self . config ,
648+ self . entropy_source_config . as_ref ( ) ,
649+ Arc :: clone ( & logger) ,
650+ ) ?;
651+
652+ let config = Arc :: new ( self . config . clone ( ) ) ;
653+
654+ let vss_xprv = derive_vss_xprv ( config, & seed_bytes, Arc :: clone ( & logger) ) ?;
655+
656+ let lnurl_auth_xprv = vss_xprv
657+ . derive_priv ( & Secp256k1 :: new ( ) , & [ ChildNumber :: Hardened { index : 138 } ] )
658+ . map_err ( |e| {
659+ log_error ! ( logger, "Failed to derive VSS secret: {}" , e) ;
660+ BuildError :: KVStoreSetupFailed
661+ } ) ?;
662+
663+ let lnurl_auth_jwt_provider =
664+ LnurlAuthToJwtProvider :: new ( lnurl_auth_xprv, lnurl_auth_server_url, fixed_headers)
665+ . map_err ( |e| {
666+ log_error ! ( logger, "Failed to create LnurlAuthToJwtProvider: {}" , e) ;
667+ BuildError :: KVStoreSetupFailed
668+ } ) ?;
669+
670+ let header_provider = Arc :: new ( lnurl_auth_jwt_provider) ;
671+
672+ self . build_vss_store_with_header_provider ( vss_url, store_id, header_provider)
673+ }
674+
675+ /// Builds a [`VssStore`] backend based implementation of [`KVStore`].
676+ pub fn build_vss_store_with_header_provider (
677+ & self , vss_url : String , store_id : String , header_provider : Arc < dyn VssHeaderProvider > ,
678+ ) -> Result < VssStore , BuildError > {
679+ let logger = setup_logger ( & self . log_writer_config , & self . config ) ?;
680+
681+ let seed_bytes = seed_bytes_from_config (
682+ & self . config ,
683+ self . entropy_source_config . as_ref ( ) ,
684+ Arc :: clone ( & logger) ,
685+ ) ?;
686+
687+ let config = Arc :: new ( self . config . clone ( ) ) ;
688+
689+ let vss_xprv = derive_vss_xprv ( config. clone ( ) , & seed_bytes, Arc :: clone ( & logger) ) ?;
690+
691+ let vss_seed_bytes: [ u8 ; 32 ] = vss_xprv. private_key . secret_bytes ( ) ;
692+
693+ Ok ( VssStore :: new ( vss_url, store_id, vss_seed_bytes, header_provider) . map_err ( |e| {
694+ log_error ! ( logger, "Failed to setup VssStore: {}" , e) ;
695+ BuildError :: KVStoreSetupFailed
696+ } ) ?)
697+ }
698+
699+ /// Builds a [`FilesystemStore`] backend based implementation of [`KVStore`].
700+ pub fn build_fs_store ( & self ) -> Result < FilesystemStore , BuildError > {
701+ let mut storage_dir_path: PathBuf = self . config . storage_dir_path . clone ( ) . into ( ) ;
702+ storage_dir_path. push ( "fs_store" ) ;
703+
704+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
705+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
706+ Ok ( FilesystemStore :: new ( storage_dir_path) )
707+ }
708+
709+ /// Builds a [`SqliteStore`] backend based implementation of [`KVStore`].
710+ pub fn build_sqlite_store ( & self ) -> Result < SqliteStore , BuildError > {
711+ let storage_dir_path = self . config . storage_dir_path . clone ( ) ;
712+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
713+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
714+
715+ Ok ( SqliteStore :: new (
716+ storage_dir_path. into ( ) ,
717+ Some ( io:: sqlite_store:: SQLITE_DB_FILE_NAME . to_string ( ) ) ,
718+ Some ( io:: sqlite_store:: KV_TABLE_NAME . to_string ( ) ) ,
719+ )
720+ . map_err ( |_| BuildError :: KVStoreSetupFailed ) ?)
721+ }
722+ }
723+
582724/// A builder for an [`Node`] instance, allowing to set some configuration and module choices from
583725/// the getgo.
584726///
0 commit comments