Browse Source

Use configure_me instead of clap

Since use of configuration files is both mmore secure and more
convenient and clap doesn't support config files, this switches to
configure_me, which supports config files, env vars and also generating
man pages.

Closes #151
master
Martin Habovstiak 5 years ago
parent
commit
ec049b9ad5
  1. 100
      Cargo.lock
  2. 8
      Cargo.toml
  3. 5
      build.rs
  4. 101
      config_spec.toml
  5. 316
      src/config.rs
  6. 2
      src/lib.rs

100
Cargo.lock

@ -138,6 +138,8 @@ dependencies = [
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
"secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_test 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -154,6 +156,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -170,6 +173,14 @@ dependencies = [
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "build-helper"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byteorder"
version = "1.3.2"
@ -244,6 +255,30 @@ dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "configure_me"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"parse_arg 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "configure_me_codegen"
version = "0.3.3"
dependencies = [
"build-helper 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fmt2io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"man 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.3"
@ -320,7 +355,8 @@ dependencies = [
"bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitcoin 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"configure_me 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"configure_me_codegen 0.3.3",
"crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -404,6 +440,11 @@ dependencies = [
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fmt2io"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fnv"
version = "1.0.6"
@ -524,6 +565,14 @@ dependencies = [
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "man"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"roff 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "matches"
version = "0.1.8"
@ -591,6 +640,11 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parse_arg"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "peeking_take_while"
version = "0.1.2"
@ -762,6 +816,11 @@ dependencies = [
"librocksdb-sys 6.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "roff"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rust-crypto"
version = "0.2.36"
@ -821,6 +880,14 @@ dependencies = [
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.9.0"
@ -859,6 +926,14 @@ dependencies = [
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_test"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "shlex"
version = "0.1.1"
@ -994,6 +1069,14 @@ dependencies = [
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ucd-util"
version = "0.1.5"
@ -1015,6 +1098,11 @@ dependencies = [
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
@ -1134,6 +1222,7 @@ dependencies = [
"checksum bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b7a2e9773ee7ae7f2560f0426c938f57902dcb9e39321b0cbd608f47ed579a4"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum build-helper 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "389803e36973d242e7fecb092b2de44a3d35ac62524b3b9339e51d577d668e02"
"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af"
@ -1143,6 +1232,7 @@ dependencies = [
"checksum clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum configure_me 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09bcca54d6219791a348ed074cb1599e47a29fbd33a23b2ba1dffc18231da6b1"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
@ -1157,6 +1247,7 @@ dependencies = [
"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fmt2io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db8691f0820ad11ce6eb94057d0dd9c456500da04da0c12a85c90d6f979cc9"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
@ -1174,6 +1265,7 @@ dependencies = [
"checksum librocksdb-sys 6.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6af56e6599bce586321e8ba8acf8a0a5e97431fd9ab49f9b69f92d93fe642c6"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum lru 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "aab390a5bd7ac223ced62fe224337c4748219145152174659291ea04ac8979c0"
"checksum man 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ccbbb1d623a3cbcaeef9a072f7ccbd6f8ca1e788f3e301d5c49bdd67b1f5a942"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
@ -1183,6 +1275,7 @@ dependencies = [
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
"checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242"
"checksum parse_arg 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0aa6995ee52a637a52261de3240eb3ffec0cfa24cb917cd03fc0365691ca24ae"
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
@ -1203,6 +1296,7 @@ dependencies = [
"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc"
"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c"
"checksum rocksdb 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e7523c32e26bf2ebc4540645961dafcbd086c652e8ecb563a507f432eb7636d"
"checksum roff 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e33e4fb37ba46888052c763e4ec2acfedd8f00f62897b630cadb6298b833675e"
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
@ -1212,11 +1306,13 @@ dependencies = [
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaccd3a23619349e0878d9a241f34b1982343cdf67367058cd7d078d326b63e"
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113"
"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
"checksum serde_test 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d8999326d1f713002c52199b3f30c052dc8998d9359d5ae950328e527da1cd"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4f61c4d59f3aaa9f61bba6450a9b80ba48362fd7d651689e7a10c453b1f6dc68"
"checksum signal-hook-registry 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "913661ac8848a61e39684a3c3e7a7a14a4deec7f54b4976d0641e70dda3939b1"
@ -1233,9 +1329,11 @@ dependencies = [
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tiny_http 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1661fa0a44c95d01604bd05c66732a446c657efb62b5164a7a083a3b552b4951"
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"

8
Cargo.toml

@ -10,6 +10,7 @@ keywords = ["bitcoin", "electrum", "server", "index", "database"]
documentation = "https://docs.rs/electrs/"
readme = "README.md"
edition = "2018"
build = "build.rs"
[profile.release]
lto = true
@ -21,9 +22,9 @@ latest_rust = [] # use latest Rust features (otherwise, support Rust 1.32)
arrayref = "0.3"
base64 = "0.10"
bincode = "1.0"
bitcoin = "0.18"
bitcoin = { version = "0.18", features = ["use-serde"] }
bitcoin_hashes = "0.3"
clap = "2.31"
configure_me = "0.3.2"
crossbeam-channel = "0.3"
dirs = "1.0"
error-chain = "0.12"
@ -45,3 +46,6 @@ stderrlog = "0.4.1"
sysconf = ">=0.3.4"
time = "0.1"
tiny_http = "0.6"
[build-dependencies]
configure_me_codegen = "0.3.4"

5
build.rs

@ -0,0 +1,5 @@
extern crate configure_me_codegen;
fn main() {
configure_me_codegen::build_script_with_man("config_spec.toml").unwrap();
}

101
config_spec.toml

@ -0,0 +1,101 @@
[general]
env_prefix = "ELECTRS"
doc = """
An efficient re-implementation of Electrum Server, inspired by ElectrumX, Electrum Personal Server and bitcoincore-indexd.
The motivation behind this project is to enable a user to run his own Electrum server, with required hardware resources not much beyond those of a full node. The server indexes the entire Bitcoin blockchain, and the resulting index enables fast queries for any given user wallet, allowing the user to keep real-time track of his balances and his transaction history using the Electrum wallet. Since it runs on the user's own machine, there is no need for the wallet to communicate with external Electrum servers, thus preserving the privacy of the user's addresses and balances."""
[[switch]]
name = "verbose"
abbr = "v"
doc = "Increase logging verbosity"
count = true
[[switch]]
name = "timestamp"
doc = "Prepend log lines with a timestamp"
[[param]]
name = "db_dir"
type = "std::path::PathBuf"
doc = "Directory to store index database (default: ./db/)"
default = "\"./db\".into()"
[[param]]
name = "daemon_dir"
type = "std::path::PathBuf"
doc = "Data directory of Bitcoind (default: ~/.bitcoin/)"
default = "crate::config::default_daemon_dir()"
[[param]]
name = "cookie"
type = "String"
doc = "JSONRPC authentication cookie ('USER:PASSWORD', default: read from ~/.bitcoin/.cookie)"
# Force the user to use config file in order to avoid password leaks
argument = false
env_var = false
[[param]]
name = "network"
type = "crate::config::BitcoinNetwork"
convert_into = "::bitcoin::network::constants::Network"
doc = "Select Bitcoin network type ('mainnet', 'testnet' or 'regtest')"
default = "Default::default()"
[[param]]
name = "electrum_rpc_addr"
type = "crate::config::ResolvAddr"
convert_into = "std::net::SocketAddr"
doc = "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)"
[[param]]
name = "daemon_rpc_addr"
type = "crate::config::ResolvAddr"
convert_into = "std::net::SocketAddr"
doc = "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)"
[[param]]
name = "monitoring_addr"
type = "crate::config::ResolvAddr"
convert_into = "std::net::SocketAddr"
doc = "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)"
[[switch]]
name = "jsonrpc_import"
doc = "Use JSONRPC instead of directly importing blk*.dat files. Useful for remote full node or low memory system"
[[param]]
name = "index_batch_size"
type = "usize"
doc = "Number of blocks to get in one JSONRPC request from bitcoind"
default = "100"
[[param]]
name = "bulk_index_threads"
type = "usize"
doc = "Number of threads used for bulk indexing (default: use the # of CPUs)"
default = "0"
[[param]]
name = "tx_cache_size"
type = "usize"
doc = "Number of transactions to keep in for query LRU cache"
default = "10000"
[[param]]
name = "blocktxids_cache_size"
type = "usize"
doc = "Number of blocks to cache transactions IDs in LRU cache"
default = "100"
[[param]]
name = "txid_limit"
type = "usize"
doc = "Number of transactions to lookup before returning an error, to prevent 'too popular' addresses from causing the RPC server to get stuck (0 - disable the limit)"
default = "100"
[[param]]
name = "server_banner"
type = "String"
doc = "The banner to be shown in the Electrum console"
default = "concat!(\"Welcome to electrs \", env!(\"CARGO_PKG_VERSION\"), \" (Electrum Rust Server)!\").to_owned()"

316
src/config.rs

@ -1,18 +1,114 @@
use bitcoin::network::constants::Network;
use clap::{App, Arg};
use dirs::home_dir;
use num_cpus;
use std::fs;
use std::fmt;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::sync::Arc;
use std::str::FromStr;
use std::ffi::{OsStr, OsString};
use std::convert::TryInto;
use stderrlog;
use crate::daemon::CookieGetter;
use crate::errors::*;
const DEFAULT_SERVER_ADDRESS: &str = "127.0.0.1"; // by default, serve on IPv4 localhost
const DEFAULT_SERVER_ADDRESS: [u8; 4] = [127, 0, 0, 1]; // by default, serve on IPv4 localhost
mod internal {
#![allow(unused)]
include!(concat!(env!("OUT_DIR"), "/configure_me_config.rs"));
}
pub enum AddressError {
InvalidUtf8(OsString),
ResolvError { addr: String, err: std::io::Error },
NoAddrError(String),
}
impl fmt::Display for AddressError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AddressError::InvalidUtf8(val) => write!(f, "{:?} isn't a valid UTF-8 sequence", val),
AddressError::ResolvError { addr, err } => write!(f, "Failed to resolve address {}: {}", addr, err),
AddressError::NoAddrError(addr) => write!(f, "No address found for {}", addr),
}
}
}
#[derive(Deserialize)]
pub struct ResolvAddr(SocketAddr);
impl ::configure_me::parse_arg::ParseArg for ResolvAddr {
type Error = AddressError;
fn parse_arg(arg: &OsStr) -> std::result::Result<Self, Self::Error> {
let arg = arg
.to_str()
.ok_or_else(|| AddressError::InvalidUtf8(arg.to_owned()))?;
arg
.to_socket_addrs().map_err(|err| AddressError::ResolvError { addr: arg.to_owned(), err })?
.next()
.ok_or_else(|| AddressError::NoAddrError(arg.to_owned()))
.map(ResolvAddr)
}
fn parse_owned_arg(arg: OsString) -> std::result::Result<Self, Self::Error> {
let arg = arg
.into_string()
.map_err(|orig| AddressError::InvalidUtf8(orig))?;
match arg.to_socket_addrs() {
Ok(mut iter) => iter.next().ok_or_else(|| AddressError::NoAddrError(arg)).map(ResolvAddr),
Err(err) => Err(AddressError::ResolvError { addr: arg, err }),
}
}
fn describe_type<W: fmt::Write>(mut writer: W) -> fmt::Result {
write!(writer, "a network address (will be resolved if needed)")
}
}
impl Into<SocketAddr> for ResolvAddr {
fn into(self) -> SocketAddr {
self.0
}
}
// `Network` uses "bitcoin" instead of "mainnet", so we have to reimplement it.
#[derive(Deserialize)]
pub struct BitcoinNetwork(Network);
impl Default for BitcoinNetwork {
fn default() -> Self {
BitcoinNetwork(Network::Bitcoin)
}
}
impl FromStr for BitcoinNetwork {
type Err = <Network as FromStr>::Err;
fn from_str(string: &str) -> std::result::Result<Self, Self::Err> {
Network::from_str(string).map(BitcoinNetwork)
}
}
impl ::configure_me::parse_arg::ParseArgFromStr for BitcoinNetwork {
fn describe_type<W: fmt::Write>(mut writer: W) -> std::fmt::Result {
write!(writer, "either 'bitcoin', 'testnet' or 'regtest'")
}
}
impl Into<Network> for BitcoinNetwork {
fn into(self) -> Network {
self.0
}
}
#[derive(Debug)]
pub struct Config {
@ -34,208 +130,86 @@ pub struct Config {
pub blocktxids_cache_size: usize,
}
fn str_to_socketaddr(address: &str, what: &str) -> SocketAddr {
address
.to_socket_addrs()
.unwrap_or_else(|e| panic!("unable to resolve {} address: {}", what, e))
.next()
.unwrap_or_else(|| panic!("no address found for {}", address))
fn default_daemon_dir() -> PathBuf {
// TODO: would be better to avoid expect()
let mut home = home_dir().expect("Unknown home directory");
home.push(".bitcoin");
home
}
impl Config {
pub fn from_args() -> Config {
let default_banner = format!(
"Welcome to electrs {} (Electrum Rust Server)!",
env!("CARGO_PKG_VERSION")
);
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("blocktxids_cache_size")
.long("blocktxids-cache-size")
.help("Number of blocks to cache transactions IDs in LRU cache")
.default_value("100")) // Needs ~0.305MB per per block at 10k txs each
.arg(
Arg::with_name("txid_limit")
.long("txid-limit")
.help("Number of transactions to lookup before returning an error, to prevent \"too popular\" addresses from causing the RPC server to get stuck (0 - disable the limit)")
.default_value("100") // should take a few seconds on a HDD
)
.arg(
Arg::with_name("server_banner")
.long("server-banner")
.help("The banner to be shown in the Electrum console")
.default_value(&default_banner)
)
.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),
use internal::ResultExt;
let system_config: &OsStr = "/etc/electrs/config.toml".as_ref();
let home_config = home_dir().map(|mut dir| { dir.push(".electrs/config.toml"); dir });
let configs = std::iter::once(system_config)
.chain(home_config.as_ref().map(AsRef::as_ref));
let (mut config, _) = internal::Config::including_optional_config_files(configs).unwrap_or_exit();
let network_name = match config.network {
Network::Bitcoin => "bitcoin",
Network::Testnet => "testnet",
Network::Regtest => "regtest",
};
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 {
config.db_dir.push(network_name);
let default_daemon_port = match config.network {
Network::Bitcoin => 8332,
Network::Testnet => 18332,
Network::Regtest => 18443,
};
let default_electrum_port = match network_type {
let default_electrum_port = match config.network {
Network::Bitcoin => 50001,
Network::Testnet => 60001,
Network::Regtest => 60401,
};
let default_monitoring_port = match network_type {
let default_monitoring_port = match config.network {
Network::Bitcoin => 4224,
Network::Testnet => 14224,
Network::Regtest => 24224,
};
let daemon_rpc_addr: SocketAddr = str_to_socketaddr(
m.value_of("daemon_rpc_addr").unwrap_or(&format!(
"{}:{}",
DEFAULT_SERVER_ADDRESS, default_daemon_port
)),
"Bitcoin RPC",
);
let electrum_rpc_addr: SocketAddr = str_to_socketaddr(
m.value_of("electrum_rpc_addr").unwrap_or(&format!(
"{}:{}",
DEFAULT_SERVER_ADDRESS, default_electrum_port
)),
"Electrum RPC",
);
let monitoring_addr: SocketAddr = str_to_socketaddr(
m.value_of("monitoring_addr").unwrap_or(&format!(
"{}:{}",
DEFAULT_SERVER_ADDRESS, default_monitoring_port
)),
"Prometheus monitoring",
);
let mut daemon_dir = m
.value_of("daemon_dir")
.map(PathBuf::from)
.unwrap_or_else(|| {
let mut default_dir = home_dir().expect("no homedir");
default_dir.push(".bitcoin");
default_dir
});
match network_type {
let daemon_rpc_addr: SocketAddr = config.daemon_rpc_addr.unwrap_or((DEFAULT_SERVER_ADDRESS, default_daemon_port).into());
let electrum_rpc_addr: SocketAddr = config.electrum_rpc_addr.unwrap_or((DEFAULT_SERVER_ADDRESS, default_electrum_port).into());
let monitoring_addr: SocketAddr = config.monitoring_addr.unwrap_or((DEFAULT_SERVER_ADDRESS, default_monitoring_port).into());
match config.network {
Network::Bitcoin => (),
Network::Testnet => daemon_dir.push("testnet3"),
Network::Regtest => daemon_dir.push("regtest"),
Network::Testnet => config.daemon_dir.push("testnet3"),
Network::Regtest => config.daemon_dir.push("regtest"),
}
let cookie = m.value_of("cookie").map(std::borrow::ToOwned::to_owned);
let mut log = stderrlog::new();
log.verbosity(m.occurrences_of("verbosity") as usize);
log.timestamp(if m.is_present("timestamp") {
log.verbosity(config.verbose.try_into().expect("Overflow: Running electrs on less than 32 bit devices is unsupported"));
log.timestamp(if config.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();
// Could have been default, but it's useful to allow the user to specify 0 when overriding
// configs.
if config.bulk_index_threads == 0 {
config.bulk_index_threads = num_cpus::get();
}
let config = Config {
log,
network_type,
db_path,
daemon_dir,
network_type: config.network,
db_path: config.db_dir,
daemon_dir: config.daemon_dir,
daemon_rpc_addr,
cookie,
cookie: config.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),
blocktxids_cache_size: value_t_or_exit!(m, "blocktxids_cache_size", usize),
txid_limit: value_t_or_exit!(m, "txid_limit", usize),
server_banner: value_t_or_exit!(m, "server_banner", String),
jsonrpc_import: config.jsonrpc_import,
index_batch_size: config.index_batch_size,
bulk_index_threads: config.bulk_index_threads,
tx_cache_size: config.tx_cache_size,
blocktxids_cache_size: config.blocktxids_cache_size,
txid_limit: config.txid_limit,
server_banner: config.server_banner,
};
eprintln!("{:?}", config);
config

2
src/lib.rs

@ -1,7 +1,5 @@
#![recursion_limit = "1024"]
#[macro_use]
extern crate clap;
#[macro_use]
extern crate arrayref;
#[macro_use]

Loading…
Cancel
Save