mirror of
https://github.com/romanz/electrs.git
synced 2024-11-19 18:10:51 +01:00
1ea6a50325
This lets the operator set a custom server banner using the configuration flag --server-banner. In addition it adds the daemon version to the banner.
244 lines
8.8 KiB
Rust
244 lines
8.8 KiB
Rust
use bitcoin::network::constants::Network;
|
|
use clap::{App, Arg};
|
|
use dirs::home_dir;
|
|
use num_cpus;
|
|
use std::fs;
|
|
use std::net::SocketAddr;
|
|
use std::path::{Path, PathBuf};
|
|
use std::sync::Arc;
|
|
use stderrlog;
|
|
|
|
use crate::daemon::CookieGetter;
|
|
use crate::errors::*;
|
|
|
|
#[derive(Debug)]
|
|
pub struct Config {
|
|
// See below for the documentation of each field:
|
|
pub log: stderrlog::StdErrLog,
|
|
pub network_type: Network,
|
|
pub db_path: PathBuf,
|
|
pub daemon_dir: PathBuf,
|
|
pub daemon_rpc_addr: SocketAddr,
|
|
pub cookie: Option<String>,
|
|
pub electrum_rpc_addr: SocketAddr,
|
|
pub monitoring_addr: SocketAddr,
|
|
pub jsonrpc_import: bool,
|
|
pub index_batch_size: usize,
|
|
pub bulk_index_threads: usize,
|
|
pub tx_cache_size: usize,
|
|
pub server_banner: String,
|
|
}
|
|
|
|
impl Config {
|
|
pub fn from_args() -> Config {
|
|
let m = App::new("Electrum Rust Server")
|
|
.version(crate_version!())
|
|
.arg(
|
|
Arg::with_name("verbosity")
|
|
.short("v")
|
|
.multiple(true)
|
|
.help("Increase logging verbosity"),
|
|
)
|
|
.arg(
|
|
Arg::with_name("timestamp")
|
|
.long("timestamp")
|
|
.help("Prepend log lines with a timestamp"),
|
|
)
|
|
.arg(
|
|
Arg::with_name("db_dir")
|
|
.long("db-dir")
|
|
.help("Directory to store index database (default: ./db/)")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("daemon_dir")
|
|
.long("daemon-dir")
|
|
.help("Data directory of Bitcoind (default: ~/.bitcoin/)")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("cookie")
|
|
.long("cookie")
|
|
.help("JSONRPC authentication cookie ('USER:PASSWORD', default: read from ~/.bitcoin/.cookie)")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("network")
|
|
.long("network")
|
|
.help("Select Bitcoin network type ('mainnet', 'testnet' or 'regtest')")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("electrum_rpc_addr")
|
|
.long("electrum-rpc-addr")
|
|
.help("Electrum server JSONRPC 'addr:port' to listen on (default: '127.0.0.1:50001' for mainnet, '127.0.0.1:60001' for testnet and '127.0.0.1:60401' for regtest)")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("daemon_rpc_addr")
|
|
.long("daemon-rpc-addr")
|
|
.help("Bitcoin daemon JSONRPC 'addr:port' to connect (default: 127.0.0.1:8332 for mainnet, 127.0.0.1:18332 for testnet and 127.0.0.1:18443 for regtest)")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("monitoring_addr")
|
|
.long("monitoring-addr")
|
|
.help("Prometheus monitoring 'addr:port' to listen on (default: 127.0.0.1:4224 for mainnet, 127.0.0.1:14224 for testnet and 127.0.0.1:24224 for regtest)")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("jsonrpc_import")
|
|
.long("jsonrpc-import")
|
|
.help("Use JSONRPC instead of directly importing blk*.dat files. Useful for remote full node or low memory system"),
|
|
)
|
|
.arg(
|
|
Arg::with_name("index_batch_size")
|
|
.long("index-batch-size")
|
|
.help("Number of blocks to get in one JSONRPC request from bitcoind")
|
|
.default_value("100"),
|
|
)
|
|
.arg(
|
|
Arg::with_name("bulk_index_threads")
|
|
.long("bulk-index-threads")
|
|
.help("Number of threads used for bulk indexing (default: use the # of CPUs)")
|
|
.default_value("0")
|
|
)
|
|
.arg(
|
|
Arg::with_name("tx_cache_size")
|
|
.long("tx-cache-size")
|
|
.help("Number of transactions to keep in for query LRU cache")
|
|
.default_value("10000") // should be enough for a small wallet.
|
|
)
|
|
.arg(
|
|
Arg::with_name("server_banner")
|
|
.long("server-banner")
|
|
.help("The banner to be shown in the Electrum console")
|
|
.default_value("Welcome to electrs (Electrum Rust Server)!")
|
|
)
|
|
.get_matches();
|
|
|
|
let network_name = m.value_of("network").unwrap_or("mainnet");
|
|
let network_type = match network_name {
|
|
"mainnet" => Network::Bitcoin,
|
|
"testnet" => Network::Testnet,
|
|
"regtest" => Network::Regtest,
|
|
_ => panic!("unsupported Bitcoin network: {:?}", network_name),
|
|
};
|
|
let db_dir = Path::new(m.value_of("db_dir").unwrap_or("./db"));
|
|
let db_path = db_dir.join(network_name);
|
|
|
|
let default_daemon_port = match network_type {
|
|
Network::Bitcoin => 8332,
|
|
Network::Testnet => 18332,
|
|
Network::Regtest => 18443,
|
|
};
|
|
let default_electrum_port = match network_type {
|
|
Network::Bitcoin => 50001,
|
|
Network::Testnet => 60001,
|
|
Network::Regtest => 60401,
|
|
};
|
|
let default_monitoring_port = match network_type {
|
|
Network::Bitcoin => 4224,
|
|
Network::Testnet => 14224,
|
|
Network::Regtest => 24224,
|
|
};
|
|
|
|
let daemon_rpc_addr: SocketAddr = m
|
|
.value_of("daemon_rpc_addr")
|
|
.unwrap_or(&format!("127.0.0.1:{}", default_daemon_port))
|
|
.parse()
|
|
.expect("invalid Bitcoind RPC address");
|
|
let electrum_rpc_addr: SocketAddr = m
|
|
.value_of("electrum_rpc_addr")
|
|
.unwrap_or(&format!("127.0.0.1:{}", default_electrum_port))
|
|
.parse()
|
|
.expect("invalid Electrum RPC address");
|
|
let monitoring_addr: SocketAddr = m
|
|
.value_of("monitoring_addr")
|
|
.unwrap_or(&format!("127.0.0.1:{}", default_monitoring_port))
|
|
.parse()
|
|
.expect("invalid Prometheus monitoring address");
|
|
|
|
let mut daemon_dir = m
|
|
.value_of("daemon_dir")
|
|
.map(|p| PathBuf::from(p))
|
|
.unwrap_or_else(|| {
|
|
let mut default_dir = home_dir().expect("no homedir");
|
|
default_dir.push(".bitcoin");
|
|
default_dir
|
|
});
|
|
match network_type {
|
|
Network::Bitcoin => (),
|
|
Network::Testnet => daemon_dir.push("testnet3"),
|
|
Network::Regtest => daemon_dir.push("regtest"),
|
|
}
|
|
let cookie = m.value_of("cookie").map(|s| s.to_owned());
|
|
|
|
let mut log = stderrlog::new();
|
|
log.verbosity(m.occurrences_of("verbosity") as usize);
|
|
log.timestamp(if m.is_present("timestamp") {
|
|
stderrlog::Timestamp::Millisecond
|
|
} else {
|
|
stderrlog::Timestamp::Off
|
|
});
|
|
log.init().expect("logging initialization failed");
|
|
let mut bulk_index_threads = value_t_or_exit!(m, "bulk_index_threads", usize);
|
|
if bulk_index_threads == 0 {
|
|
bulk_index_threads = num_cpus::get();
|
|
}
|
|
let config = Config {
|
|
log,
|
|
network_type,
|
|
db_path,
|
|
daemon_dir,
|
|
daemon_rpc_addr,
|
|
cookie,
|
|
electrum_rpc_addr,
|
|
monitoring_addr,
|
|
jsonrpc_import: m.is_present("jsonrpc_import"),
|
|
index_batch_size: value_t_or_exit!(m, "index_batch_size", usize),
|
|
bulk_index_threads,
|
|
tx_cache_size: value_t_or_exit!(m, "tx_cache_size", usize),
|
|
server_banner: value_t_or_exit!(m, "server_banner", String),
|
|
};
|
|
eprintln!("{:?}", config);
|
|
config
|
|
}
|
|
|
|
pub fn cookie_getter(&self) -> Arc<CookieGetter> {
|
|
if let Some(ref value) = self.cookie {
|
|
Arc::new(StaticCookie {
|
|
value: value.as_bytes().to_vec(),
|
|
})
|
|
} else {
|
|
Arc::new(CookieFile {
|
|
daemon_dir: self.daemon_dir.clone(),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
struct StaticCookie {
|
|
value: Vec<u8>,
|
|
}
|
|
|
|
impl CookieGetter for StaticCookie {
|
|
fn get(&self) -> Result<Vec<u8>> {
|
|
Ok(self.value.clone())
|
|
}
|
|
}
|
|
|
|
struct CookieFile {
|
|
daemon_dir: PathBuf,
|
|
}
|
|
|
|
impl CookieGetter for CookieFile {
|
|
fn get(&self) -> Result<Vec<u8>> {
|
|
let path = self.daemon_dir.join(".cookie");
|
|
let contents = fs::read(&path).chain_err(|| {
|
|
ErrorKind::Connection(format!("failed to read cookie from {:?}", path))
|
|
})?;
|
|
Ok(contents)
|
|
}
|
|
}
|