@@ -15,6 +15,7 @@ use std::{fs, io};
1515use clap:: Parser ;
1616use ldk_node:: bitcoin:: secp256k1:: PublicKey ;
1717use ldk_node:: bitcoin:: Network ;
18+ use ldk_node:: config:: { HRNResolverConfig , HumanReadableNamesConfig } ;
1819use ldk_node:: lightning:: ln:: msgs:: SocketAddress ;
1920use ldk_node:: lightning:: routing:: gossip:: NodeAlias ;
2021use ldk_node:: liquidity:: LSPS2ServiceConfig ;
@@ -61,6 +62,7 @@ pub struct Config {
6162 pub metrics_username : Option < String > ,
6263 pub metrics_password : Option < String > ,
6364 pub tor_config : Option < TorConfig > ,
65+ pub hrn_config : HumanReadableNamesConfig ,
6466}
6567
6668#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -114,6 +116,7 @@ struct ConfigBuilder {
114116 metrics_username : Option < String > ,
115117 metrics_password : Option < String > ,
116118 tor_proxy_address : Option < String > ,
119+ hrn : Option < HrnTomlConfig > ,
117120}
118121
119122impl ConfigBuilder {
@@ -180,6 +183,10 @@ impl ConfigBuilder {
180183 if let Some ( tor) = toml. tor {
181184 self . tor_proxy_address = Some ( tor. proxy_address )
182185 }
186+
187+ if let Some ( hrn) = toml. hrn {
188+ self . hrn = Some ( hrn) ;
189+ }
183190 }
184191
185192 fn merge_args ( & mut self , args : & ArgsConfig ) {
@@ -402,6 +409,11 @@ impl ConfigBuilder {
402409 } )
403410 . transpose ( ) ?;
404411
412+ let hrn_config = match self . hrn {
413+ Some ( hrn) => HumanReadableNamesConfig :: try_from ( hrn) ?,
414+ None => HumanReadableNamesConfig :: default ( ) ,
415+ } ;
416+
405417 Ok ( Config {
406418 network,
407419 listening_addrs,
@@ -422,6 +434,7 @@ impl ConfigBuilder {
422434 metrics_username,
423435 metrics_password,
424436 tor_config : tor_proxy_address. map ( |proxy_address| TorConfig { proxy_address } ) ,
437+ hrn_config,
425438 } )
426439 }
427440}
@@ -439,6 +452,7 @@ pub struct TomlConfig {
439452 tls : Option < TomlTlsConfig > ,
440453 metrics : Option < MetricsTomlConfig > ,
441454 tor : Option < TomlTorConfig > ,
455+ hrn : Option < HrnTomlConfig > ,
442456}
443457
444458#[ derive( Deserialize , Serialize ) ]
@@ -505,6 +519,52 @@ struct TomlTorConfig {
505519 proxy_address : String ,
506520}
507521
522+ #[ derive( Deserialize , Serialize ) ]
523+ struct HrnTomlConfig {
524+ mode : Option < String > ,
525+ dns_server_address : Option < String > ,
526+ enable_resolution_service : Option < bool > ,
527+ }
528+
529+ impl TryFrom < HrnTomlConfig > for HumanReadableNamesConfig {
530+ type Error = io:: Error ;
531+
532+ fn try_from ( value : HrnTomlConfig ) -> Result < Self , Self :: Error > {
533+ let mut config = HumanReadableNamesConfig :: default ( ) ;
534+
535+ match value. mode . as_deref ( ) {
536+ None | Some ( "dns" ) => { } ,
537+ Some ( "blip32" ) => {
538+ config. resolution_config = HRNResolverConfig :: Blip32 ;
539+ } ,
540+ Some ( other) => {
541+ return Err ( io:: Error :: new (
542+ io:: ErrorKind :: InvalidInput ,
543+ format ! ( "Invalid HRN mode '{}' configured; expected 'dns' or 'blip32'" , other) ,
544+ ) )
545+ } ,
546+ }
547+
548+ if let HRNResolverConfig :: Dns { dns_server_address, enable_hrn_resolution_service } =
549+ & mut config. resolution_config
550+ {
551+ if let Some ( addr) = value. dns_server_address . as_deref ( ) {
552+ * dns_server_address = SocketAddress :: from_str ( addr) . map_err ( |e| {
553+ io:: Error :: new (
554+ io:: ErrorKind :: InvalidInput ,
555+ format ! ( "Invalid HRN DNS server address configured: {}" , e) ,
556+ )
557+ } ) ?;
558+ }
559+ if let Some ( enable) = value. enable_resolution_service {
560+ * enable_hrn_resolution_service = enable;
561+ }
562+ }
563+
564+ Ok ( config)
565+ }
566+ }
567+
508568#[ derive( Deserialize , Serialize ) ]
509569struct LiquidityConfig {
510570 lsps2_client : Option < LSPSClientTomlConfig > ,
@@ -936,6 +996,7 @@ mod tests {
936996 tor_config : Some ( TorConfig {
937997 proxy_address : SocketAddress :: from_str ( "127.0.0.1:9050" ) . unwrap ( ) ,
938998 } ) ,
999+ hrn_config : HumanReadableNamesConfig :: default ( ) ,
9391000 } ;
9401001
9411002 assert_eq ! ( config. listening_addrs, expected. listening_addrs) ;
@@ -1241,6 +1302,7 @@ mod tests {
12411302 metrics_username : None ,
12421303 metrics_password : None ,
12431304 tor_config : None ,
1305+ hrn_config : HumanReadableNamesConfig :: default ( ) ,
12441306 } ;
12451307
12461308 assert_eq ! ( config. listening_addrs, expected. listening_addrs) ;
@@ -1350,6 +1412,7 @@ mod tests {
13501412 tor_config : Some ( TorConfig {
13511413 proxy_address : SocketAddress :: from_str ( "127.0.0.1:9050" ) . unwrap ( ) ,
13521414 } ) ,
1415+ hrn_config : HumanReadableNamesConfig :: default ( ) ,
13531416 } ;
13541417
13551418 assert_eq ! ( config. listening_addrs, expected. listening_addrs) ;
@@ -1501,4 +1564,81 @@ mod tests {
15011564 let err = result. unwrap_err ( ) ;
15021565 assert_eq ! ( err. kind( ) , io:: ErrorKind :: InvalidInput ) ;
15031566 }
1567+
1568+ #[ test]
1569+ fn test_hrn_config ( ) {
1570+ let storage_path = std:: env:: temp_dir ( ) ;
1571+ let config_file_name = "test_hrn_config.toml" ;
1572+
1573+ let base_config = r#"
1574+ [node]
1575+ network = "regtest"
1576+
1577+ [bitcoind]
1578+ rpc_address = "127.0.0.1:8332"
1579+ rpc_user = "bitcoind-testuser"
1580+ rpc_password = "bitcoind-testpassword"
1581+
1582+ [liquidity.lsps2_service]
1583+ advertise_service = false
1584+ channel_opening_fee_ppm = 1000
1585+ channel_over_provisioning_ppm = 500000
1586+ min_channel_opening_fee_msat = 10000000
1587+ min_channel_lifetime = 4320
1588+ max_client_to_self_delay = 1440
1589+ min_payment_size_msat = 10000000
1590+ max_payment_size_msat = 25000000000
1591+ client_trusts_lsp = true
1592+ disable_client_reserve = false
1593+ "# ;
1594+
1595+ let mut args_config = empty_args_config ( ) ;
1596+ args_config. config_file =
1597+ Some ( storage_path. join ( config_file_name) . to_string_lossy ( ) . to_string ( ) ) ;
1598+
1599+ // Default: no `[hrn]` section -> DNS against 8.8.8.8:53, resolution service disabled.
1600+ fs:: write ( storage_path. join ( config_file_name) , base_config) . unwrap ( ) ;
1601+ let config = load_config ( & args_config) . unwrap ( ) ;
1602+ match config. hrn_config . resolution_config {
1603+ HRNResolverConfig :: Dns { dns_server_address, enable_hrn_resolution_service } => {
1604+ assert_eq ! ( dns_server_address, SocketAddress :: from_str( "8.8.8.8:53" ) . unwrap( ) ) ;
1605+ assert ! ( !enable_hrn_resolution_service) ;
1606+ } ,
1607+ other => panic ! ( "unexpected default HRN resolver config: {:?}" , other) ,
1608+ }
1609+
1610+ // Custom DNS server address with resolution service enabled.
1611+ let toml_config = format ! (
1612+ "{}\n [hrn]\n dns_server_address = \" 1.1.1.1:53\" \n enable_resolution_service = true\n " ,
1613+ base_config
1614+ ) ;
1615+ fs:: write ( storage_path. join ( config_file_name) , & toml_config) . unwrap ( ) ;
1616+ let config = load_config ( & args_config) . unwrap ( ) ;
1617+ match config. hrn_config . resolution_config {
1618+ HRNResolverConfig :: Dns { dns_server_address, enable_hrn_resolution_service } => {
1619+ assert_eq ! ( dns_server_address, SocketAddress :: from_str( "1.1.1.1:53" ) . unwrap( ) ) ;
1620+ assert ! ( enable_hrn_resolution_service) ;
1621+ } ,
1622+ other => panic ! ( "unexpected HRN resolver config: {:?}" , other) ,
1623+ }
1624+
1625+ // Blip32 mode.
1626+ let toml_config = format ! ( "{}\n [hrn]\n mode = \" blip32\" \n " , base_config) ;
1627+ fs:: write ( storage_path. join ( config_file_name) , & toml_config) . unwrap ( ) ;
1628+ let config = load_config ( & args_config) . unwrap ( ) ;
1629+ assert ! ( matches!( config. hrn_config. resolution_config, HRNResolverConfig :: Blip32 ) ) ;
1630+
1631+ // Invalid mode is rejected.
1632+ let toml_config = format ! ( "{}\n [hrn]\n mode = \" bogus\" \n " , base_config) ;
1633+ fs:: write ( storage_path. join ( config_file_name) , & toml_config) . unwrap ( ) ;
1634+ let err = load_config ( & args_config) . unwrap_err ( ) ;
1635+ assert_eq ! ( err. kind( ) , io:: ErrorKind :: InvalidInput ) ;
1636+
1637+ // Invalid DNS server address is rejected.
1638+ let toml_config =
1639+ format ! ( "{}\n [hrn]\n dns_server_address = \" not-a-socket-address\" \n " , base_config) ;
1640+ fs:: write ( storage_path. join ( config_file_name) , & toml_config) . unwrap ( ) ;
1641+ let err = load_config ( & args_config) . unwrap_err ( ) ;
1642+ assert_eq ! ( err. kind( ) , io:: ErrorKind :: InvalidInput ) ;
1643+ }
15041644}
0 commit comments