Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 96 additions & 80 deletions ldk-server/src/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,36 +185,39 @@ impl ConfigBuilder {
.parse::<SocketAddr>()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;

let storage_dir_path =
self.storage_dir_path.ok_or_else(|| missing_field_err("storage_dir_path"))?;

let listening_addrs = self
let listening_addrs: Option<Vec<SocketAddress>> = self
.listening_addresses
.ok_or_else(|| missing_field_err("node_listening_addresses"))?
.into_iter()
.map(|addr| {
SocketAddress::from_str(&addr).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid listening addresses configured: {}", e),
)
})
.map(|addrs| {
addrs
.into_iter()
.map(|addr| {
SocketAddress::from_str(&addr).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid listening addresses configured: {}", e),
)
})
})
.collect::<Result<Vec<_>, _>>()
})
.collect::<Result<Vec<_>, _>>()?;
.transpose()?;

let announcement_addrs = self
let announcement_addrs: Option<Vec<SocketAddress>> = self
.announcement_addresses
.ok_or_else(|| missing_field_err("node_announcement_addresses"))?
.into_iter()
.map(|addr| {
SocketAddress::from_str(&addr).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid announcement addresses configured: {}", e),
)
})
.map(|addrs| {
addrs
.into_iter()
.map(|addr| {
SocketAddress::from_str(&addr).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid announcement addresses configured: {}", e),
)
})
})
.collect::<Result<Vec<_>, _>>()
})
.collect::<Result<Vec<_>, _>>()?;
.transpose()?;

let alias = self
.alias
Expand Down Expand Up @@ -325,12 +328,12 @@ impl ConfigBuilder {

Ok(Config {
network,
listening_addrs: Some(listening_addrs),
announcement_addrs: Some(announcement_addrs),
listening_addrs,
announcement_addrs,
alias,
tls_config: self.tls_config,
rest_service_addr,
storage_dir_path: Some(storage_dir_path),
storage_dir_path: self.storage_dir_path,
chain_source,
rabbitmq_connection_string,
rabbitmq_exchange_name,
Expand Down Expand Up @@ -650,6 +653,21 @@ mod tests {
}
}

fn empty_args_config() -> ArgsConfig {
ArgsConfig {
config_file: None,
node_network: None,
node_listening_addresses: None,
node_announcement_addresses: None,
node_rest_service_address: None,
node_alias: None,
bitcoind_rpc_address: None,
bitcoind_rpc_user: None,
bitcoind_rpc_password: None,
storage_dir_path: None,
}
}

fn missing_field_msg(field: &str) -> String {
format!(
"Missing `{}`. Please provide it via config file, CLI argument, or environment variable.",
Expand All @@ -663,18 +681,10 @@ mod tests {
let config_file_name = "test_config_from_file.toml";

fs::write(storage_path.join(config_file_name), DEFAULT_CONFIG).unwrap();
let args_config = ArgsConfig {
config_file: Some(storage_path.join(config_file_name).to_string_lossy().to_string()),
node_network: None,
node_listening_addresses: None,
node_announcement_addresses: None,
node_rest_service_address: None,
bitcoind_rpc_address: None,
bitcoind_rpc_user: None,
bitcoind_rpc_password: None,
storage_dir_path: None,
node_alias: None,
};

let mut args_config = empty_args_config();
args_config.config_file =
Some(storage_path.join(config_file_name).to_string_lossy().to_string());

let config = load_config(&args_config).unwrap();

Expand Down Expand Up @@ -891,22 +901,54 @@ mod tests {
assert_eq!(error.to_string(), "Must set a single chain source, multiple were configured");
}

#[test]
fn test_config_optional_values() {
let storage_path = std::env::temp_dir();
let config_file_name = "test_only_required_config.toml";

let mut args_config = empty_args_config();
args_config.config_file =
Some(storage_path.join(config_file_name).to_string_lossy().to_string());

// Test with optional values not specified in the config file
let toml_config = r#"
[node]
network = "regtest"
rest_service_address = "127.0.0.1:3002"

[bitcoind]
rpc_address = "127.0.0.1:8332" # RPC endpoint
rpc_user = "bitcoind-testuser"
rpc_password = "bitcoind-testpassword"

[rabbitmq]
connection_string = "rabbitmq_connection_string"
exchange_name = "rabbitmq_exchange_name"

[liquidity.lsps2_service]
advertise_service = false
channel_opening_fee_ppm = 1000 # 0.1% fee
channel_over_provisioning_ppm = 500000 # 50% extra capacity
min_channel_opening_fee_msat = 10000000 # 10,000 satoshis
min_channel_lifetime = 4320 # ~30 days
max_client_to_self_delay = 1440 # ~10 days
min_payment_size_msat = 10000000 # 10,000 satoshis
max_payment_size_msat = 25000000000 # 0.25 BTC
client_trusts_lsp = true
"#;

fs::write(storage_path.join(config_file_name), toml_config).unwrap();
assert!(load_config(&args_config).is_ok());
}

#[test]
fn test_config_missing_fields_in_file() {
let storage_path = std::env::temp_dir();
let config_file_name = "test_config_missing_fields_in_file.toml";
let args_config = ArgsConfig {
config_file: Some(storage_path.join(config_file_name).to_string_lossy().to_string()),
node_network: None,
node_listening_addresses: None,
node_announcement_addresses: None,
node_rest_service_address: None,
bitcoind_rpc_address: None,
bitcoind_rpc_user: None,
bitcoind_rpc_password: None,
storage_dir_path: None,
node_alias: None,
};

let mut args_config = empty_args_config();
args_config.config_file =
Some(storage_path.join(config_file_name).to_string_lossy().to_string());

macro_rules! validate_missing {
($field:expr, $err_msg:expr) => {
Expand Down Expand Up @@ -940,9 +982,7 @@ mod tests {
validate_missing!("rpc_password", missing_field_msg("bitcoind_rpc_password"));
validate_missing!("rpc_user", missing_field_msg("bitcoind_rpc_user"));
validate_missing!("rpc_address", missing_field_msg("bitcoind_rpc_address"));
validate_missing!("dir_path =", missing_field_msg("storage_dir_path"));
validate_missing!("rest_service_address =", missing_field_msg("rest_service_address"));
validate_missing!("listening_addresses =", missing_field_msg("node_listening_addresses"));
validate_missing!("network =", missing_field_msg("network"));
}

Expand Down Expand Up @@ -1025,8 +1065,6 @@ mod tests {
validate_missing!(bitcoind_rpc_address, missing_field_msg("bitcoind_rpc_address"));
validate_missing!(node_network, missing_field_msg("network"));
validate_missing!(node_rest_service_address, missing_field_msg("rest_service_address"));
validate_missing!(storage_dir_path, missing_field_msg("storage_dir_path"));
validate_missing!(node_listening_addresses, missing_field_msg("node_listening_addresses"));
}

#[test]
Expand Down Expand Up @@ -1109,18 +1147,7 @@ mod tests {
#[test]
#[cfg(feature = "events-rabbitmq")]
fn test_error_if_rabbitmq_feature_without_valid_config_file() {
let args_config = ArgsConfig {
config_file: None,
node_network: None,
node_listening_addresses: None,
node_announcement_addresses: None,
node_rest_service_address: None,
node_alias: None,
bitcoind_rpc_address: None,
bitcoind_rpc_user: None,
bitcoind_rpc_password: None,
storage_dir_path: None,
};
let args_config = empty_args_config();
let result = load_config(&args_config);
assert!(result.is_err());
let err = result.unwrap_err();
Expand All @@ -1130,18 +1157,7 @@ mod tests {
#[test]
#[cfg(feature = "experimental-lsps2-support")]
fn test_error_if_lsps2_feature_without_valid_config_file() {
let args_config = ArgsConfig {
config_file: None,
node_network: None,
node_listening_addresses: None,
node_announcement_addresses: None,
node_rest_service_address: None,
node_alias: None,
bitcoind_rpc_address: None,
bitcoind_rpc_user: None,
bitcoind_rpc_password: None,
storage_dir_path: None,
};
let args_config = empty_args_config();
let result = load_config(&args_config);
assert!(result.is_err());
let err = result.unwrap_err();
Expand Down