fedimint_gateway_server/
config.rs

1use std::net::SocketAddr;
2use std::path::PathBuf;
3use std::str::FromStr;
4
5use bitcoin::Network;
6use clap::{ArgGroup, Parser};
7use fedimint_core::envs::{FM_IROH_DNS_ENV, FM_IROH_RELAY_ENV};
8use fedimint_core::util::SafeUrl;
9use fedimint_gateway_common::{LightningMode, V1_API_ENDPOINT};
10use fedimint_lnv2_common::gateway_api::PaymentFee;
11
12use super::envs;
13use crate::envs::{
14    FM_BITCOIND_PASSWORD_ENV, FM_BITCOIND_URL_ENV, FM_BITCOIND_USERNAME_ENV, FM_ESPLORA_URL_ENV,
15    FM_GATEWAY_METRICS_LISTEN_ADDR_ENV, FM_GATEWAY_SKIP_SETUP_ENV,
16};
17
18#[derive(Debug, Clone, Copy, clap::ValueEnum)]
19pub enum DatabaseBackend {
20    /// Use RocksDB database backend
21    #[value(name = "rocksdb")]
22    RocksDb,
23    /// Use CursedRedb database backend (hybrid memory/redb)
24    #[value(name = "cursed-redb")]
25    CursedRedb,
26}
27
28/// Command line parameters for starting the gateway. `mode`, `data_dir`,
29/// `listen`, and `api_addr` are all required.
30#[derive(Parser)]
31#[command(version)]
32#[command(
33    group(
34        ArgGroup::new("bitcoind_password_auth")
35           .args(["bitcoind_password"])
36           .multiple(false)
37    ),
38    group(
39        ArgGroup::new("bitcoind_auth")
40            .args(["bitcoind_url"])
41            .requires("bitcoind_password_auth")
42            .requires_all(["bitcoind_username", "bitcoind_url"])
43    ),
44    group(
45        ArgGroup::new("bitcoin_rpc")
46            .required(true)
47            .multiple(true)
48            .args(["bitcoind_url", "esplora_url"])
49    )
50)]
51pub struct GatewayOpts {
52    #[clap(subcommand)]
53    pub mode: LightningMode,
54
55    /// Path to folder containing gateway config and data files
56    #[arg(long = "data-dir", env = envs::FM_GATEWAY_DATA_DIR_ENV)]
57    pub data_dir: PathBuf,
58
59    /// Gateway webserver listen address
60    #[arg(long = "listen", env = envs::FM_GATEWAY_LISTEN_ADDR_ENV)]
61    listen: SocketAddr,
62
63    /// Public URL from which the webserver API is reachable
64    #[arg(long = "api-addr", env = envs::FM_GATEWAY_API_ADDR_ENV)]
65    api_addr: Option<SafeUrl>,
66
67    /// Gateway webserver authentication bcrypt password hash
68    #[arg(long = "bcrypt-password-hash", env = envs::FM_GATEWAY_BCRYPT_PASSWORD_HASH_ENV)]
69    bcrypt_password_hash: String,
70
71    /// Bitcoin network this gateway will be running on
72    #[arg(long = "network", env = envs::FM_GATEWAY_NETWORK_ENV)]
73    network: Network,
74
75    /// Number of route hints to return in invoices
76    #[arg(
77        long = "num-route-hints",
78        env = envs::FM_NUMBER_OF_ROUTE_HINTS_ENV,
79        default_value_t = super::DEFAULT_NUM_ROUTE_HINTS
80    )]
81    num_route_hints: u32,
82
83    /// Database backend to use.
84    #[arg(long, env = envs::FM_DB_BACKEND_ENV, value_enum, default_value = "rocksdb")]
85    pub db_backend: DatabaseBackend,
86
87    /// The username to use when connecting to bitcoind
88    #[arg(long, env = FM_BITCOIND_USERNAME_ENV)]
89    pub bitcoind_username: Option<String>,
90
91    /// The password to use when connecting to bitcoind
92    #[arg(long, env = FM_BITCOIND_PASSWORD_ENV)]
93    pub bitcoind_password: Option<String>,
94
95    /// Bitcoind RPC URL, e.g. <http://127.0.0.1:8332>
96    /// This should not include authentication parameters, they should be
97    /// included in `FM_BITCOIND_USERNAME` and `FM_BITCOIND_PASSWORD`
98    #[arg(long, env = FM_BITCOIND_URL_ENV)]
99    pub bitcoind_url: Option<SafeUrl>,
100
101    /// Esplora HTTP base URL, e.g. <https://mempool.space/api>
102    #[arg(long, env = FM_ESPLORA_URL_ENV)]
103    pub esplora_url: Option<SafeUrl>,
104
105    /// The default routing fees that are applied to new federations
106    #[arg(long = "default-routing-fees", env = envs::FM_DEFAULT_ROUTING_FEES_ENV, default_value_t = PaymentFee::TRANSACTION_FEE_DEFAULT)]
107    default_routing_fees: PaymentFee,
108
109    /// The default transaction fees that are applied to new federations
110    #[arg(long = "default-transaction-fees", env = envs::FM_DEFAULT_TRANSACTION_FEES_ENV, default_value_t = PaymentFee::TRANSACTION_FEE_DEFAULT)]
111    default_transaction_fees: PaymentFee,
112
113    /// Gateway iroh listen address
114    #[arg(long = "iroh-listen", env = envs::FM_GATEWAY_IROH_LISTEN_ADDR_ENV)]
115    iroh_listen: Option<SocketAddr>,
116
117    /// Gateway metrics listen address. If not set, defaults to localhost on the
118    /// UI port + 1.
119    #[arg(long = "metrics-listen", env = FM_GATEWAY_METRICS_LISTEN_ADDR_ENV)]
120    metrics_listen: Option<SocketAddr>,
121
122    /// Optional URL of the Iroh DNS server
123    #[arg(long, env = FM_IROH_DNS_ENV)]
124    iroh_dns: Option<SafeUrl>,
125
126    /// Optional URLs of the Iroh relays to use for registering
127    #[arg(long, env = FM_IROH_RELAY_ENV)]
128    iroh_relays: Vec<SafeUrl>,
129
130    #[arg(long, env = FM_GATEWAY_SKIP_SETUP_ENV, default_value_t = false)]
131    skip_setup: bool,
132}
133
134impl GatewayOpts {
135    /// Converts the command line parameters into a helper struct the Gateway
136    /// uses to store runtime parameters.
137    pub fn to_gateway_parameters(&self) -> anyhow::Result<GatewayParameters> {
138        let versioned_api = self.api_addr.clone().map(|api_addr| {
139            api_addr
140                .join(V1_API_ENDPOINT)
141                .expect("Could not join v1 api_addr")
142        });
143        let bcrypt_password_hash = bcrypt::HashParts::from_str(&self.bcrypt_password_hash)?;
144
145        // Default metrics listen to localhost on UI port + 1
146        let metrics_listen = self.metrics_listen.unwrap_or_else(|| {
147            SocketAddr::new(
148                std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST),
149                self.listen.port() + 1,
150            )
151        });
152
153        Ok(GatewayParameters {
154            listen: self.listen,
155            versioned_api,
156            bcrypt_password_hash,
157            network: self.network,
158            num_route_hints: self.num_route_hints,
159            default_routing_fees: self.default_routing_fees,
160            default_transaction_fees: self.default_transaction_fees,
161            iroh_listen: self.iroh_listen,
162            iroh_dns: self.iroh_dns.clone(),
163            iroh_relays: self.iroh_relays.clone(),
164            skip_setup: self.skip_setup,
165            metrics_listen,
166        })
167    }
168}
169
170/// `GatewayParameters` is a helper struct that can be derived from
171/// `GatewayOpts` that holds the CLI or environment variables that are specified
172/// by the user.
173///
174/// If `GatewayConfiguration is set in the database, that takes precedence and
175/// the optional parameters will have no affect.
176#[derive(Debug)]
177pub struct GatewayParameters {
178    pub listen: SocketAddr,
179    pub versioned_api: Option<SafeUrl>,
180    pub bcrypt_password_hash: bcrypt::HashParts,
181    pub network: Network,
182    pub num_route_hints: u32,
183    pub default_routing_fees: PaymentFee,
184    pub default_transaction_fees: PaymentFee,
185    pub iroh_listen: Option<SocketAddr>,
186    pub iroh_dns: Option<SafeUrl>,
187    pub iroh_relays: Vec<SafeUrl>,
188    pub skip_setup: bool,
189    pub metrics_listen: SocketAddr,
190}