fedimint_core/
envs.rs

1use std::env;
2
3use anyhow::Context;
4use fedimint_core::util::SafeUrl;
5use fedimint_derive::{Decodable, Encodable};
6use fedimint_logging::LOG_CORE;
7use jsonrpsee_core::Serialize;
8use serde::Deserialize;
9use tracing::warn;
10
11/// In tests we want to routinely enable an extra unknown module to ensure
12/// all client code handles correct modules that client doesn't know about.
13pub const FM_USE_UNKNOWN_MODULE_ENV: &str = "FM_USE_UNKNOWN_MODULE";
14
15pub const FM_ENABLE_MODULE_LNV2_ENV: &str = "FM_ENABLE_MODULE_LNV2";
16/// In certain devimint cases (e.g. upgrade tests), we'd like to test things
17/// without enabling lnv2. This should make deviming stop setting
18/// `FM_ENABLE_MODULE_LNV2_ENV`
19pub const FM_DEVIMINT_DISABLE_MODULE_LNV2_ENV: &str = "FM_DEVIMINT_DISABLE_MODULE_LNV2";
20
21/// Check if env variable is set and not equal `0` or `false` which are common
22/// ways to disable something.
23pub fn is_env_var_set(var: &str) -> bool {
24    std::env::var_os(var).is_some_and(|v| v != "0" && v != "false")
25}
26
27/// Use to detect if running in a test environment, either `cargo test` or
28/// `devimint`.
29pub fn is_running_in_test_env() -> bool {
30    let unit_test = cfg!(test);
31
32    unit_test || is_env_var_set("NEXTEST") || is_env_var_set(FM_IN_DEVIMINT_ENV)
33}
34
35/// Use to allow `process_output` to process RBF withdrawal outputs.
36pub fn is_rbf_withdrawal_enabled() -> bool {
37    is_env_var_set("FM_UNSAFE_ENABLE_RBF_WITHDRAWAL")
38}
39
40/// Get value of `FEDIMINT_BUILD_CODE_VERSION` at compile time
41#[macro_export]
42macro_rules! fedimint_build_code_version_env {
43    () => {
44        env!("FEDIMINT_BUILD_CODE_VERSION")
45    };
46}
47
48/// Env var for bitcoin RPC kind (obsolete, use FM_DEFAULT_* instead)
49pub const FM_BITCOIN_RPC_KIND_ENV: &str = "FM_BITCOIN_RPC_KIND";
50/// Env var for bitcoin URL (obsolete, use FM_DEFAULT_* instead)
51pub const FM_BITCOIN_RPC_URL_ENV: &str = "FM_BITCOIN_RPC_URL";
52/// Env var how often to poll bitcoin source
53pub const FM_BITCOIN_POLLING_INTERVAL_SECS_ENV: &str = "FM_BITCOIN_POLLING_INTERVAL_SECS";
54
55/// Env var for bitcoin RPC kind (default, used only as a default value for DKG
56/// config settings)
57pub const FM_DEFAULT_BITCOIN_RPC_KIND_ENV: &str = "FM_DEFAULT_BITCOIN_RPC_KIND";
58pub const FM_DEFAULT_BITCOIN_RPC_KIND_BAD_ENV: &str = "FM_DEFAULT_BITCOIND_RPC_KIND";
59/// Env var for bitcoin URL (default, used only as a default value for DKG
60/// config settings)
61pub const FM_DEFAULT_BITCOIN_RPC_URL_ENV: &str = "FM_DEFAULT_BITCOIN_RPC_URL";
62pub const FM_DEFAULT_BITCOIN_RPC_URL_BAD_ENV: &str = "FM_DEFAULT_BITCOIND_RPC_URL";
63
64/// Env var for bitcoin RPC kind (forced, takes priority over config settings)
65pub const FM_FORCE_BITCOIN_RPC_KIND_ENV: &str = "FM_FORCE_BITCOIN_RPC_KIND";
66pub const FM_FORCE_BITCOIN_RPC_KIND_BAD_ENV: &str = "FM_FORCE_BITCOIND_RPC_BAD_KIND";
67/// Env var for bitcoin URL (default, takes priority over config settings)
68pub const FM_FORCE_BITCOIN_RPC_URL_ENV: &str = "FM_FORCE_BITCOIN_RPC_URL";
69pub const FM_FORCE_BITCOIN_RPC_URL_BAD_ENV: &str = "FM_FORCE_BITCOIND_RPC_URL";
70
71/// List of json api endpoint sources to use as a source of
72/// fee rate estimation.
73///
74/// `;`-separated list of urls with part after `#`
75/// ("fragment") specifying jq filter to extract sats/vB fee rate.
76/// Eg. `https://mempool.space/api/v1/fees/recommended#.halfHourFee`
77///
78/// Note that `#` is a standalone separator and *not* parsed as a part of the
79/// Url. Which means there's no need to escape it.
80pub const FM_WALLET_FEERATE_SOURCES_ENV: &str = "FM_WALLET_FEERATE_SOURCES";
81
82/// Env var that can be set to point at the bitcoind's cookie file to use for
83/// auth
84pub const FM_BITCOIND_COOKIE_FILE_ENV: &str = "FM_BITCOIND_COOKIE_FILE";
85
86/// `devimint` will set when code is running inside `devimint`
87pub const FM_IN_DEVIMINT_ENV: &str = "FM_IN_DEVIMINT";
88
89/// Configuration for the bitcoin RPC
90#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
91pub struct BitcoinRpcConfig {
92    pub kind: String,
93    pub url: SafeUrl,
94}
95
96impl BitcoinRpcConfig {
97    pub fn get_defaults_from_env_vars() -> anyhow::Result<Self> {
98        Ok(Self {
99        kind: env::var(FM_FORCE_BITCOIN_RPC_KIND_ENV)
100            .or_else(|_| env::var(FM_DEFAULT_BITCOIN_RPC_KIND_ENV))
101            .or_else(|_| env::var(FM_BITCOIN_RPC_KIND_ENV).inspect(|_v| {
102                warn!(target: LOG_CORE, "{FM_BITCOIN_RPC_KIND_ENV} is obsolete, use {FM_DEFAULT_BITCOIN_RPC_KIND_ENV} instead");
103            }))
104            .or_else(|_| env::var(FM_FORCE_BITCOIN_RPC_KIND_BAD_ENV).inspect(|_v| {
105                warn!(target: LOG_CORE, "{FM_FORCE_BITCOIN_RPC_KIND_BAD_ENV} is obsolete, use {FM_FORCE_BITCOIN_RPC_KIND_ENV} instead");
106            }))
107            .or_else(|_| env::var(FM_DEFAULT_BITCOIN_RPC_KIND_BAD_ENV).inspect(|_v| {
108                warn!(target: LOG_CORE, "{FM_DEFAULT_BITCOIN_RPC_KIND_BAD_ENV} is obsolete, use {FM_DEFAULT_BITCOIN_RPC_KIND_ENV} instead");
109            }))
110            .with_context(|| {
111                anyhow::anyhow!("failure looking up env var for Bitcoin RPC kind")
112            })?,
113        url: env::var(FM_FORCE_BITCOIN_RPC_URL_ENV)
114            .or_else(|_| env::var(FM_DEFAULT_BITCOIN_RPC_URL_ENV))
115            .or_else(|_| env::var(FM_BITCOIN_RPC_URL_ENV).inspect(|_v| {
116                warn!(target: LOG_CORE, "{FM_BITCOIN_RPC_URL_ENV} is obsolete, use {FM_DEFAULT_BITCOIN_RPC_URL_ENV} instead");
117            }))
118            .or_else(|_| env::var(FM_FORCE_BITCOIN_RPC_URL_BAD_ENV).inspect(|_v| {
119                warn!(target: LOG_CORE, "{FM_FORCE_BITCOIN_RPC_URL_BAD_ENV} is obsolete, use {FM_FORCE_BITCOIN_RPC_URL_ENV} instead");
120            }))
121            .or_else(|_| env::var(FM_DEFAULT_BITCOIN_RPC_URL_BAD_ENV).inspect(|_v| {
122                warn!(target: LOG_CORE, "{FM_DEFAULT_BITCOIN_RPC_URL_BAD_ENV} is obsolete, use {FM_DEFAULT_BITCOIN_RPC_URL_ENV} instead");
123            }))
124            .with_context(|| {
125                anyhow::anyhow!("failure looking up env var for Bitcoin RPC URL")
126            })?
127            .parse()
128            .with_context(|| {
129                anyhow::anyhow!("failure parsing Bitcoin RPC URL")
130            })?,
131    })
132    }
133}