Skip to content
Merged
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions ldk-server/ldk-server-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ rest_service_address = "127.0.0.1:3002" # LDK Server REST address
[storage.disk]
dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence


# Must set either bitcoind or esplora settings, but not both

# Bitcoin Core settings
[bitcoind]
rpc_address = "127.0.0.1:18444" # RPC endpoint
rpc_user = "polaruser" # RPC username
rpc_password = "polarpass" # RPC password

# Esplora settings
[esplora]
server_url = "https://mempool.space/api" # Esplora endpoint

# RabbitMQ settings (only required if using events-rabbitmq feature)
[rabbitmq]
connection_string = "" # RabbitMQ connection string
Expand Down
23 changes: 14 additions & 9 deletions ldk-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::io::persist::{
FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE,
PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE,
};
use crate::util::config::load_config;
use crate::util::config::{load_config, ChainSource};
use crate::util::proto_adapter::{forwarded_payment_to_proto, payment_to_proto};
use hex::DisplayHex;
use ldk_node::config::Config;
Expand Down Expand Up @@ -79,14 +79,19 @@ fn main() {
let mut builder = Builder::from_config(ldk_node_config);
builder.set_log_facade_logger();

let bitcoind_rpc_addr = config_file.bitcoind_rpc_addr;

builder.set_chain_source_bitcoind_rpc(
bitcoind_rpc_addr.ip().to_string(),
bitcoind_rpc_addr.port(),
config_file.bitcoind_rpc_user,
config_file.bitcoind_rpc_password,
);
match config_file.chain_source {
ChainSource::Rpc { rpc_address, rpc_user, rpc_password } => {
builder.set_chain_source_bitcoind_rpc(
rpc_address.ip().to_string(),
rpc_address.port(),
rpc_user,
rpc_password,
);
},
ChainSource::Esplora { server_url } => {
builder.set_chain_source_esplora(server_url, None);
},
}

// LSPS2 support is highly experimental and for testing purposes only.
#[cfg(feature = "experimental-lsps2-support")]
Expand Down
155 changes: 132 additions & 23 deletions ldk-server/src/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ pub struct Config {
pub network: Network,
pub rest_service_addr: SocketAddr,
pub storage_dir_path: String,
pub bitcoind_rpc_addr: SocketAddr,
pub bitcoind_rpc_user: String,
pub bitcoind_rpc_password: String,
pub chain_source: ChainSource,
pub rabbitmq_connection_string: String,
pub rabbitmq_exchange_name: String,
pub lsps2_service_config: Option<LSPS2ServiceConfig>,
}

#[derive(Debug)]
pub enum ChainSource {
Rpc { rpc_address: SocketAddr, rpc_user: String, rpc_password: String },
Esplora { server_url: String },
}

impl TryFrom<TomlConfig> for Config {
type Error = io::Error;

Expand All @@ -42,13 +46,30 @@ impl TryFrom<TomlConfig> for Config {
format!("Invalid rest service address configured: {}", e),
)
})?;
let bitcoind_rpc_addr =
SocketAddr::from_str(&toml_config.bitcoind.rpc_address).map_err(|e| {
io::Error::new(
let chain_source = match (toml_config.esplora, toml_config.bitcoind) {
(Some(EsploraConfig { server_url }), None) => ChainSource::Esplora { server_url },
(None, Some(BitcoindConfig { rpc_address, rpc_user, rpc_password })) => {
let rpc_address = SocketAddr::from_str(&rpc_address).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid bitcoind RPC address configured: {}", e),
)
})?;
ChainSource::Rpc { rpc_address, rpc_user, rpc_password }
},
(Some(_), Some(_)) => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid bitcoind RPC address configured: {}", e),
)
})?;
format!("Must set a single chain source, multiple were configured"),
))
},
(None, None) => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("At least one chain source must be set, either bitcoind or esplora"),
))
},
};

let alias = if let Some(alias_str) = toml_config.node.alias {
let mut bytes = [0u8; 32];
Expand Down Expand Up @@ -97,9 +118,7 @@ impl TryFrom<TomlConfig> for Config {
alias,
rest_service_addr,
storage_dir_path: toml_config.storage.disk.dir_path,
bitcoind_rpc_addr,
bitcoind_rpc_user: toml_config.bitcoind.rpc_user,
bitcoind_rpc_password: toml_config.bitcoind.rpc_password,
chain_source,
rabbitmq_connection_string,
rabbitmq_exchange_name,
lsps2_service_config,
Expand All @@ -112,7 +131,8 @@ impl TryFrom<TomlConfig> for Config {
pub struct TomlConfig {
node: NodeConfig,
storage: StorageConfig,
bitcoind: BitcoindConfig,
bitcoind: Option<BitcoindConfig>,
esplora: Option<EsploraConfig>,
rabbitmq: Option<RabbitmqConfig>,
liquidity: Option<LiquidityConfig>,
}
Expand Down Expand Up @@ -142,6 +162,11 @@ struct BitcoindConfig {
rpc_password: String,
}

#[derive(Deserialize, Serialize)]
struct EsploraConfig {
server_url: String,
}

#[derive(Deserialize, Serialize)]
struct RabbitmqConfig {
connection_string: String,
Expand Down Expand Up @@ -233,10 +258,8 @@ mod tests {
[storage.disk]
dir_path = "/tmp"

[bitcoind]
rpc_address = "127.0.0.1:8332" # RPC endpoint
rpc_user = "bitcoind-testuser"
rpc_password = "bitcoind-testpassword"
[esplora]
server_url = "https://mempool.space/api"

[rabbitmq]
connection_string = "rabbitmq_connection_string"
Expand Down Expand Up @@ -266,9 +289,9 @@ mod tests {
network: Network::Regtest,
rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(),
storage_dir_path: "/tmp".to_string(),
bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(),
bitcoind_rpc_user: "bitcoind-testuser".to_string(),
bitcoind_rpc_password: "bitcoind-testpassword".to_string(),
chain_source: ChainSource::Esplora {
server_url: String::from("https://mempool.space/api"),
},
rabbitmq_connection_string: "rabbitmq_connection_string".to_string(),
rabbitmq_exchange_name: "rabbitmq_exchange_name".to_string(),
lsps2_service_config: Some(LSPS2ServiceConfig {
Expand All @@ -288,12 +311,98 @@ mod tests {
assert_eq!(config.network, expected.network);
assert_eq!(config.rest_service_addr, expected.rest_service_addr);
assert_eq!(config.storage_dir_path, expected.storage_dir_path);
assert_eq!(config.bitcoind_rpc_addr, expected.bitcoind_rpc_addr);
assert_eq!(config.bitcoind_rpc_user, expected.bitcoind_rpc_user);
assert_eq!(config.bitcoind_rpc_password, expected.bitcoind_rpc_password);
let ChainSource::Esplora { server_url } = config.chain_source else {
panic!("unexpected config chain source");
};
let ChainSource::Esplora { server_url: expected_server_url } = expected.chain_source else {
panic!("unexpected chain source");
};
assert_eq!(server_url, expected_server_url);
assert_eq!(config.rabbitmq_connection_string, expected.rabbitmq_connection_string);
assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name);
#[cfg(feature = "experimental-lsps2-support")]
assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some());

// Test case where only bitcoind is set

let toml_config = r#"
[node]
network = "regtest"
listening_address = "localhost:3001"
rest_service_address = "127.0.0.1:3002"
alias = "LDK Server"

[storage.disk]
dir_path = "/tmp"

[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
"#;

fs::write(storage_path.join(config_file_name), toml_config).unwrap();
let config = load_config(storage_path.join(config_file_name)).unwrap();

let ChainSource::Rpc { rpc_address, rpc_user, rpc_password } = config.chain_source else {
panic!("unexpected chain source");
};

assert_eq!(rpc_address, SocketAddr::from_str("127.0.0.1:8332").unwrap());
assert_eq!(rpc_user, "bitcoind-testuser");
assert_eq!(rpc_password, "bitcoind-testpassword");

// Test case where both bitcoind and esplora are set, resulting in an error

let toml_config = r#"
[node]
network = "regtest"
listening_address = "localhost:3001"
rest_service_address = "127.0.0.1:3002"
alias = "LDK Server"

[storage.disk]
dir_path = "/tmp"

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

[esplora]
server_url = "https://mempool.space/api"

[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
"#;

fs::write(storage_path.join(config_file_name), toml_config).unwrap();
let error = load_config(storage_path.join(config_file_name)).unwrap_err();
assert_eq!(error.to_string(), "Must set a single chain source, multiple were configured");
}
}