@@ -16,14 +16,18 @@ pub struct Config {
1616 pub network : Network ,
1717 pub rest_service_addr : SocketAddr ,
1818 pub storage_dir_path : String ,
19- pub bitcoind_rpc_addr : SocketAddr ,
20- pub bitcoind_rpc_user : String ,
21- pub bitcoind_rpc_password : String ,
19+ pub chain_source : ChainSource ,
2220 pub rabbitmq_connection_string : String ,
2321 pub rabbitmq_exchange_name : String ,
2422 pub lsps2_service_config : Option < LSPS2ServiceConfig > ,
2523}
2624
25+ #[ derive( Debug ) ]
26+ pub enum ChainSource {
27+ Rpc { rpc_address : SocketAddr , rpc_user : String , rpc_password : String } ,
28+ Esplora { server_url : String } ,
29+ }
30+
2731impl TryFrom < TomlConfig > for Config {
2832 type Error = io:: Error ;
2933
@@ -42,13 +46,30 @@ impl TryFrom<TomlConfig> for Config {
4246 format ! ( "Invalid rest service address configured: {}" , e) ,
4347 )
4448 } ) ?;
45- let bitcoind_rpc_addr =
46- SocketAddr :: from_str ( & toml_config. bitcoind . rpc_address ) . map_err ( |e| {
47- io:: Error :: new (
49+ let chain_source = match ( toml_config. esplora , toml_config. bitcoind ) {
50+ ( Some ( EsploraConfig { server_url } ) , None ) => ChainSource :: Esplora { server_url } ,
51+ ( None , Some ( BitcoindConfig { rpc_address, rpc_user, rpc_password } ) ) => {
52+ let rpc_address = SocketAddr :: from_str ( & rpc_address) . map_err ( |e| {
53+ io:: Error :: new (
54+ io:: ErrorKind :: InvalidInput ,
55+ format ! ( "Invalid bitcoind RPC address configured: {}" , e) ,
56+ )
57+ } ) ?;
58+ ChainSource :: Rpc { rpc_address, rpc_user, rpc_password }
59+ } ,
60+ ( Some ( _) , Some ( _) ) => {
61+ return Err ( io:: Error :: new (
4862 io:: ErrorKind :: InvalidInput ,
49- format ! ( "Invalid bitcoind RPC address configured: {}" , e) ,
50- )
51- } ) ?;
63+ format ! ( "Must set a single chain source, multiple were configured" ) ,
64+ ) )
65+ } ,
66+ ( None , None ) => {
67+ return Err ( io:: Error :: new (
68+ io:: ErrorKind :: InvalidInput ,
69+ format ! ( "At least one chain source must be set, either bitcoind or esplora" ) ,
70+ ) )
71+ } ,
72+ } ;
5273
5374 let alias = if let Some ( alias_str) = toml_config. node . alias {
5475 let mut bytes = [ 0u8 ; 32 ] ;
@@ -97,9 +118,7 @@ impl TryFrom<TomlConfig> for Config {
97118 alias,
98119 rest_service_addr,
99120 storage_dir_path : toml_config. storage . disk . dir_path ,
100- bitcoind_rpc_addr,
101- bitcoind_rpc_user : toml_config. bitcoind . rpc_user ,
102- bitcoind_rpc_password : toml_config. bitcoind . rpc_password ,
121+ chain_source,
103122 rabbitmq_connection_string,
104123 rabbitmq_exchange_name,
105124 lsps2_service_config,
@@ -112,7 +131,8 @@ impl TryFrom<TomlConfig> for Config {
112131pub struct TomlConfig {
113132 node : NodeConfig ,
114133 storage : StorageConfig ,
115- bitcoind : BitcoindConfig ,
134+ bitcoind : Option < BitcoindConfig > ,
135+ esplora : Option < EsploraConfig > ,
116136 rabbitmq : Option < RabbitmqConfig > ,
117137 liquidity : Option < LiquidityConfig > ,
118138}
@@ -142,6 +162,11 @@ struct BitcoindConfig {
142162 rpc_password : String ,
143163}
144164
165+ #[ derive( Deserialize , Serialize ) ]
166+ struct EsploraConfig {
167+ server_url : String ,
168+ }
169+
145170#[ derive( Deserialize , Serialize ) ]
146171struct RabbitmqConfig {
147172 connection_string : String ,
@@ -233,10 +258,8 @@ mod tests {
233258 [storage.disk]
234259 dir_path = "/tmp"
235260
236- [bitcoind]
237- rpc_address = "127.0.0.1:8332" # RPC endpoint
238- rpc_user = "bitcoind-testuser"
239- rpc_password = "bitcoind-testpassword"
261+ [esplora]
262+ server_url = "https://mempool.space/api"
240263
241264 [rabbitmq]
242265 connection_string = "rabbitmq_connection_string"
@@ -266,9 +289,9 @@ mod tests {
266289 network : Network :: Regtest ,
267290 rest_service_addr : SocketAddr :: from_str ( "127.0.0.1:3002" ) . unwrap ( ) ,
268291 storage_dir_path : "/tmp" . to_string ( ) ,
269- bitcoind_rpc_addr : SocketAddr :: from_str ( "127.0.0.1:8332" ) . unwrap ( ) ,
270- bitcoind_rpc_user : "bitcoind-testuser" . to_string ( ) ,
271- bitcoind_rpc_password : "bitcoind-testpassword" . to_string ( ) ,
292+ chain_source : ChainSource :: Esplora {
293+ server_url : String :: from ( "https://mempool.space/api" ) ,
294+ } ,
272295 rabbitmq_connection_string : "rabbitmq_connection_string" . to_string ( ) ,
273296 rabbitmq_exchange_name : "rabbitmq_exchange_name" . to_string ( ) ,
274297 lsps2_service_config : Some ( LSPS2ServiceConfig {
@@ -288,12 +311,98 @@ mod tests {
288311 assert_eq ! ( config. network, expected. network) ;
289312 assert_eq ! ( config. rest_service_addr, expected. rest_service_addr) ;
290313 assert_eq ! ( config. storage_dir_path, expected. storage_dir_path) ;
291- assert_eq ! ( config. bitcoind_rpc_addr, expected. bitcoind_rpc_addr) ;
292- assert_eq ! ( config. bitcoind_rpc_user, expected. bitcoind_rpc_user) ;
293- assert_eq ! ( config. bitcoind_rpc_password, expected. bitcoind_rpc_password) ;
314+ let ChainSource :: Esplora { server_url } = config. chain_source else {
315+ panic ! ( "unexpected config chain source" ) ;
316+ } ;
317+ let ChainSource :: Esplora { server_url : expected_server_url } = expected. chain_source else {
318+ panic ! ( "unexpected chain source" ) ;
319+ } ;
320+ assert_eq ! ( server_url, expected_server_url) ;
294321 assert_eq ! ( config. rabbitmq_connection_string, expected. rabbitmq_connection_string) ;
295322 assert_eq ! ( config. rabbitmq_exchange_name, expected. rabbitmq_exchange_name) ;
296323 #[ cfg( feature = "experimental-lsps2-support" ) ]
297324 assert_eq ! ( config. lsps2_service_config. is_some( ) , expected. lsps2_service_config. is_some( ) ) ;
325+
326+ // Test case where only bitcoind is set
327+
328+ let toml_config = r#"
329+ [node]
330+ network = "regtest"
331+ listening_address = "localhost:3001"
332+ rest_service_address = "127.0.0.1:3002"
333+ alias = "LDK Server"
334+
335+ [storage.disk]
336+ dir_path = "/tmp"
337+
338+ [bitcoind]
339+ rpc_address = "127.0.0.1:8332" # RPC endpoint
340+ rpc_user = "bitcoind-testuser"
341+ rpc_password = "bitcoind-testpassword"
342+
343+ [rabbitmq]
344+ connection_string = "rabbitmq_connection_string"
345+ exchange_name = "rabbitmq_exchange_name"
346+
347+ [liquidity.lsps2_service]
348+ advertise_service = false
349+ channel_opening_fee_ppm = 1000 # 0.1% fee
350+ channel_over_provisioning_ppm = 500000 # 50% extra capacity
351+ min_channel_opening_fee_msat = 10000000 # 10,000 satoshis
352+ min_channel_lifetime = 4320 # ~30 days
353+ max_client_to_self_delay = 1440 # ~10 days
354+ min_payment_size_msat = 10000000 # 10,000 satoshis
355+ max_payment_size_msat = 25000000000 # 0.25 BTC
356+ "# ;
357+
358+ fs:: write ( storage_path. join ( config_file_name) , toml_config) . unwrap ( ) ;
359+ let config = load_config ( storage_path. join ( config_file_name) ) . unwrap ( ) ;
360+
361+ let ChainSource :: Rpc { rpc_address, rpc_user, rpc_password } = config. chain_source else {
362+ panic ! ( "unexpected chain source" ) ;
363+ } ;
364+
365+ assert_eq ! ( rpc_address, SocketAddr :: from_str( "127.0.0.1:8332" ) . unwrap( ) ) ;
366+ assert_eq ! ( rpc_user, "bitcoind-testuser" ) ;
367+ assert_eq ! ( rpc_password, "bitcoind-testpassword" ) ;
368+
369+ // Test case where both bitcoind and esplora are set, resulting in an error
370+
371+ let toml_config = r#"
372+ [node]
373+ network = "regtest"
374+ listening_address = "localhost:3001"
375+ rest_service_address = "127.0.0.1:3002"
376+ alias = "LDK Server"
377+
378+ [storage.disk]
379+ dir_path = "/tmp"
380+
381+ [bitcoind]
382+ rpc_address = "127.0.0.1:8332" # RPC endpoint
383+ rpc_user = "bitcoind-testuser"
384+ rpc_password = "bitcoind-testpassword"
385+
386+ [esplora]
387+ server_url = "https://mempool.space/api"
388+
389+ [rabbitmq]
390+ connection_string = "rabbitmq_connection_string"
391+ exchange_name = "rabbitmq_exchange_name"
392+
393+ [liquidity.lsps2_service]
394+ advertise_service = false
395+ channel_opening_fee_ppm = 1000 # 0.1% fee
396+ channel_over_provisioning_ppm = 500000 # 50% extra capacity
397+ min_channel_opening_fee_msat = 10000000 # 10,000 satoshis
398+ min_channel_lifetime = 4320 # ~30 days
399+ max_client_to_self_delay = 1440 # ~10 days
400+ min_payment_size_msat = 10000000 # 10,000 satoshis
401+ max_payment_size_msat = 25000000000 # 0.25 BTC
402+ "# ;
403+
404+ fs:: write ( storage_path. join ( config_file_name) , toml_config) . unwrap ( ) ;
405+ let error = load_config ( storage_path. join ( config_file_name) ) . unwrap_err ( ) ;
406+ assert_eq ! ( error. to_string( ) , "Must set a single chain source, multiple were configured" ) ;
298407 }
299408}
0 commit comments