@@ -460,6 +460,7 @@ impl ConfigBuilder {
460460
461461/// Configuration loaded from a TOML file.
462462#[ derive( Deserialize , Serialize ) ]
463+ #[ serde( deny_unknown_fields) ]
463464pub struct TomlConfig {
464465 node : Option < NodeConfig > ,
465466 storage : Option < StorageConfig > ,
@@ -475,6 +476,7 @@ pub struct TomlConfig {
475476}
476477
477478#[ derive( Deserialize , Serialize ) ]
479+ #[ serde( deny_unknown_fields) ]
478480struct NodeConfig {
479481 network : Option < Network > ,
480482 listening_addresses : Option < Vec < String > > ,
@@ -487,46 +489,54 @@ struct NodeConfig {
487489}
488490
489491#[ derive( Deserialize , Serialize ) ]
492+ #[ serde( deny_unknown_fields) ]
490493struct StorageConfig {
491494 disk : Option < DiskConfig > ,
492495}
493496
494497#[ derive( Deserialize , Serialize ) ]
498+ #[ serde( deny_unknown_fields) ]
495499struct DiskConfig {
496500 dir_path : Option < String > ,
497501}
498502
499503#[ derive( Deserialize , Serialize ) ]
504+ #[ serde( deny_unknown_fields) ]
500505struct BitcoindConfig {
501506 rpc_address : Option < String > ,
502507 rpc_user : Option < String > ,
503508 rpc_password : Option < String > ,
504509}
505510
506511#[ derive( Deserialize , Serialize ) ]
512+ #[ serde( deny_unknown_fields) ]
507513struct ElectrumConfig {
508514 server_url : String ,
509515}
510516
511517#[ derive( Deserialize , Serialize ) ]
518+ #[ serde( deny_unknown_fields) ]
512519struct EsploraConfig {
513520 server_url : String ,
514521}
515522
516523#[ derive( Deserialize , Serialize ) ]
524+ #[ serde( deny_unknown_fields) ]
517525struct LogConfig {
518526 level : Option < String > ,
519527 file : Option < String > ,
520528}
521529
522530#[ derive( Deserialize , Serialize ) ]
531+ #[ serde( deny_unknown_fields) ]
523532struct TomlTlsConfig {
524533 cert_path : Option < String > ,
525534 key_path : Option < String > ,
526535 hosts : Option < Vec < String > > ,
527536}
528537
529538#[ derive( Deserialize , Serialize ) ]
539+ #[ serde( deny_unknown_fields) ]
530540struct MetricsTomlConfig {
531541 enabled : Option < bool > ,
532542 poll_metrics_interval : Option < u64 > ,
@@ -535,11 +545,13 @@ struct MetricsTomlConfig {
535545}
536546
537547#[ derive( Deserialize , Serialize ) ]
548+ #[ serde( deny_unknown_fields) ]
538549struct TomlTorConfig {
539550 proxy_address : String ,
540551}
541552
542553#[ derive( Deserialize , Serialize ) ]
554+ #[ serde( deny_unknown_fields) ]
543555struct HrnTomlConfig {
544556 mode : Option < String > ,
545557 dns_server_address : Option < String > ,
@@ -645,19 +657,22 @@ fn parse_async_payments_role(role: &str) -> io::Result<AsyncPaymentsRole> {
645657}
646658
647659#[ derive( Deserialize , Serialize ) ]
660+ #[ serde( deny_unknown_fields) ]
648661struct LiquidityConfig {
649662 lsps2_client : Option < LSPSClientTomlConfig > ,
650663 lsps2_service : Option < LSPS2ServiceTomlConfig > ,
651664}
652665
653666#[ derive( Deserialize , Serialize , Debug ) ]
667+ #[ serde( deny_unknown_fields) ]
654668struct LSPSClientTomlConfig {
655669 node_pubkey : String ,
656670 address : String ,
657671 token : Option < String > ,
658672}
659673
660674#[ derive( Deserialize , Serialize , Debug ) ]
675+ #[ serde( deny_unknown_fields) ]
661676struct LSPS2ServiceTomlConfig {
662677 advertise_service : bool ,
663678 channel_opening_fee_ppm : u32 ,
@@ -1343,6 +1358,73 @@ mod tests {
13431358 validate_missing ! ( "network =" , missing_field_msg( "network" ) ) ;
13441359 }
13451360
1361+ #[ test]
1362+ fn test_config_unknown_fields_in_file ( ) {
1363+ let storage_path = std:: env:: temp_dir ( ) ;
1364+ let config_file_name = "test_config_unknown_fields_in_file.toml" ;
1365+
1366+ let mut args_config = empty_args_config ( ) ;
1367+ args_config. config_file =
1368+ Some ( storage_path. join ( config_file_name) . to_string_lossy ( ) . to_string ( ) ) ;
1369+
1370+ fs:: write (
1371+ storage_path. join ( config_file_name) ,
1372+ format ! ( "{}\n [unknown]\n option = true\n " , DEFAULT_CONFIG ) ,
1373+ )
1374+ . unwrap ( ) ;
1375+ let err = load_config ( & args_config) . unwrap_err ( ) ;
1376+ assert_eq ! ( err. kind( ) , io:: ErrorKind :: InvalidData ) ;
1377+ assert ! ( err. to_string( ) . contains( "unknown field `unknown`" ) ) ;
1378+
1379+ fs:: write (
1380+ storage_path. join ( config_file_name) ,
1381+ DEFAULT_CONFIG
1382+ . replace ( "network = \" regtest\" " , "network = \" regtest\" \n unknown = true" ) ,
1383+ )
1384+ . unwrap ( ) ;
1385+ let err = load_config ( & args_config) . unwrap_err ( ) ;
1386+ assert_eq ! ( err. kind( ) , io:: ErrorKind :: InvalidData ) ;
1387+ assert ! ( err. to_string( ) . contains( "unknown field `unknown`" ) ) ;
1388+ }
1389+
1390+ #[ test]
1391+ #[ cfg( not( feature = "experimental-lsps2-support" ) ) ]
1392+ fn test_config_allows_unused_lsps2_service_config_without_feature ( ) {
1393+ let storage_path = std:: env:: temp_dir ( ) ;
1394+ let config_file_name =
1395+ "test_config_allows_unused_lsps2_service_config_without_feature.toml" ;
1396+
1397+ let mut args_config = empty_args_config ( ) ;
1398+ args_config. config_file =
1399+ Some ( storage_path. join ( config_file_name) . to_string_lossy ( ) . to_string ( ) ) ;
1400+
1401+ let toml_config = r#"
1402+ [node]
1403+ network = "regtest"
1404+
1405+ [bitcoind]
1406+ rpc_address = "127.0.0.1:8332"
1407+ rpc_user = "bitcoind-testuser"
1408+ rpc_password = "bitcoind-testpassword"
1409+
1410+ [liquidity.lsps2_service]
1411+ advertise_service = false
1412+ channel_opening_fee_ppm = 1000
1413+ channel_over_provisioning_ppm = 500000
1414+ min_channel_opening_fee_msat = 10000000
1415+ min_channel_lifetime = 4320
1416+ max_client_to_self_delay = 1440
1417+ min_payment_size_msat = 10000000
1418+ max_payment_size_msat = 25000000000
1419+ client_trusts_lsp = true
1420+ disable_client_reserve = false
1421+ "# ;
1422+
1423+ fs:: write ( storage_path. join ( config_file_name) , toml_config) . unwrap ( ) ;
1424+ let config = load_config ( & args_config) . unwrap ( ) ;
1425+ assert ! ( config. lsps2_service_config. is_none( ) ) ;
1426+ }
1427+
13461428 fn remove_config_line ( config : & str , key : & str ) -> String {
13471429 config
13481430 . lines ( )
@@ -1573,7 +1655,6 @@ mod tests {
15731655 let toml_config = r#"
15741656 [node]
15751657 network = "regtest"
1576- rest_service_address = "127.0.0.1:3002"
15771658
15781659 [bitcoind]
15791660 rpc_address = "127.0.0.1:8332"
@@ -1585,10 +1666,6 @@ mod tests {
15851666 username = "admin"
15861667 password = "password123"
15871668
1588- [rabbitmq]
1589- connection_string = "rabbitmq_connection_string"
1590- exchange_name = "rabbitmq_exchange_name"
1591-
15921669 [liquidity.lsps2_service]
15931670 advertise_service = false
15941671 channel_opening_fee_ppm = 1000 # 0.1% fee
@@ -1621,7 +1698,6 @@ mod tests {
16211698 let toml_config = r#"
16221699 [node]
16231700 network = "regtest"
1624- rest_service_address = "127.0.0.1:3002"
16251701
16261702 [bitcoind]
16271703 rpc_address = "127.0.0.1:8332"
@@ -1632,10 +1708,6 @@ mod tests {
16321708 enabled = true
16331709 username = "admin"
16341710
1635- [rabbitmq]
1636- connection_string = "rabbitmq_connection_string"
1637- exchange_name = "rabbitmq_exchange_name"
1638-
16391711 [liquidity.lsps2_service]
16401712 advertise_service = false
16411713 channel_opening_fee_ppm = 1000 # 0.1% fee
0 commit comments