Skip to content

Conversation

moisesPompilio
Copy link
Contributor

Added support for configuring the node via CLI arguments and environment variables, using clap (as already done in ldk-server-cli).

Configuration is now loaded from three sources:

  1. Config file (most complete set of options)
  2. Environment variables (essential options only)
  3. CLI arguments (essential options only)

Environment variables and CLI arguments override values defined in the config file when provided.

In addition, the bitcoind_rpc_addr field was split into two variables for better clarity:

  • bitcoind_rpc_host
  • bitcoind_rpc_port

Tests were added for the new configuration loading logic, and the README was updated with usage instructions.

close #42 and #66

- Added `clap` dependency to `ldk-server` to
  support passing essential node config via CLI arguments and environment
  variables.
- Implemented layered config loading: config file (full set of options) +
  environment variables + CLI arguments. Env vars and CLI args override
  values from the config file when present.
- Split `bitcoind_rpc_addr` into `bitcoind_rpc_host` and `bitcoind_rpc_port`
  for clearer configuration.
- Added tests for the new config loading logic.
- Updated README with usage instructions and explanation of config precedence.
@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Aug 21, 2025

I've assigned @jkczyz as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@ldk-reviews-bot ldk-reviews-bot requested a review from jkczyz August 21, 2025 13:10
@Anyitechs
Copy link

Thank you for your work on this!

I'm still going through the changes, but I have an early high-level question. Is there a reason or trade-off why the clap crate is preferred over the config crate for this?

My initial thought was that a crate like config might be a better fit here, since it's specifically designed for layered configuration and helps separate config loading from CLI argument parsing.

Just want to make sure I understand the design decision.

@moisesPompilio
Copy link
Contributor Author

I chose to use clap because it was already a dependency in ldk-server-cli and it provides built-in support for both CLI arguments and environment variables. This made it convenient to extend ldk-server without introducing a new dependency, so clap seemed like a good fit for this use case.

I hadn’t considered using a separate configuration crate like config for this, so I didn’t research that option.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @jkczyz! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @jkczyz! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling these issues! Looks like CI is failing, though.

None
};

macro_rules! pick {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH, the call sites may be more readable if everything was explicitly written out. There isn't much happening here, so I don't think it would be too verbose.

Comment on lines -140 to +61
rpc_address: String,
rpc_user: String,
rpc_password: String,
rpc_host: Option<String>,
rpc_port: Option<u16>,
rpc_user: Option<String>,
rpc_password: Option<String>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you make a separate commit for splitting the RPC address?


macro_rules! pick {
($cli:expr, $toml:expr, $err_msg:expr) => {
$cli.or($toml).ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, $err_msg))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or_else?

};
}

fn missing_field_msg(field: &str) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this return the io::Error instead? Then the unrolled macro would be less verbose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

config via environment variables
4 participants