use std::path::PathBuf;
use std::{env, fmt};
use bitcoin::Network;
use crate::config::Config;
const DEFAULT_EXTRA_ARGS: [&str; 2] = ["-prune=0", "-txindex"];
#[derive(Debug)]
pub struct UnsupportedNetwork;
impl std::fmt::Display for UnsupportedNetwork {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "unsupported network")
}
}
impl std::error::Error for UnsupportedNetwork {}
#[derive(Clone)]
pub struct TestConfig {
pub network: Network,
pub rpc_port: u16,
pub rpc_username: String,
pub rpc_password: String,
pub bitcoind_path: Option<PathBuf>,
pub extra_args: Vec<String>,
}
impl fmt::Debug for TestConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TestConfig")
.field("network", &self.network)
.field("rpc_port", &self.rpc_port)
.field("rpc_username", &"[redacted]")
.field("rpc_password", &"[redacted]")
.field("bitcoind_path", &self.bitcoind_path)
.field("extra_args", &self.extra_args)
.finish()
}
}
impl TestConfig {
pub fn as_chain_str(&self) -> Result<&'static str, UnsupportedNetwork> {
#[allow(unreachable_patterns)]
match self.network {
Network::Bitcoin => Ok("main"),
Network::Regtest => Ok("regtest"),
Network::Signet => Ok("signet"),
Network::Testnet => Ok("testnet"),
Network::Testnet4 => Ok("testnet4"),
_ => Err(UnsupportedNetwork),
}
}
pub fn network_from_str(s: &str) -> Option<Network> {
match s.to_ascii_lowercase().as_str() {
"regtest" => Some(Network::Regtest),
"testnet" | "test" => Some(Network::Testnet),
"signet" => Some(Network::Signet),
"mainnet" | "main" | "bitcoin" => Some(Network::Bitcoin),
"testnet4" => Some(Network::Testnet4),
_ => None,
}
}
#[allow(clippy::field_reassign_with_default)]
pub fn from_env() -> Self {
let mut cfg = Self::default();
if let Ok(net) = env::var("RPC_NETWORK") {
if let Some(n) = Self::network_from_str(&net) {
cfg.network = n;
}
}
if let Ok(port_str) = env::var("RPC_PORT") {
if let Ok(port) = port_str.parse() {
cfg.rpc_port = port;
}
}
if let Ok(user) = env::var("RPC_USER") {
cfg.rpc_username = user;
}
if let Ok(pass) = env::var("RPC_PASS") {
cfg.rpc_password = pass;
}
if let Ok(path) = env::var("BITCOIND_PATH") {
cfg.bitcoind_path = Some(PathBuf::from(path));
}
cfg
}
pub fn into_config(self) -> Config {
Config {
rpc_url: format!("http://127.0.0.1:{}", self.rpc_port),
rpc_user: self.rpc_username,
rpc_password: self.rpc_password,
}
}
pub fn from_config(config: &Config) -> Self {
let rpc_port =
config.rpc_url.split(':').next_back().and_then(|s| s.parse().ok()).unwrap_or(0);
Self {
network: Network::Regtest, rpc_port,
rpc_username: config.rpc_user.clone(),
rpc_password: config.rpc_password.clone(),
bitcoind_path: None,
extra_args: DEFAULT_EXTRA_ARGS.map(String::from).to_vec(),
}
}
}
impl Default for TestConfig {
fn default() -> Self {
Self {
network: Network::Regtest,
rpc_port: 0,
rpc_username: "rpcuser".to_string(),
rpc_password: "rpcpassword".to_string(),
bitcoind_path: None,
extra_args: DEFAULT_EXTRA_ARGS.map(String::from).to_vec(),
}
}
}