poa-bridge/src/config.rs

228 lines
5.7 KiB
Rust
Raw Normal View History

2017-06-25 04:21:13 -07:00
use std::path::{PathBuf, Path};
use std::fs;
use std::io::Read;
2017-08-01 02:36:48 -07:00
use std::time::Duration;
2017-08-03 15:48:12 -07:00
use web3::types::Address;
2017-08-02 03:45:15 -07:00
use error::{ResultExt, Error};
2017-06-25 04:21:13 -07:00
use toml;
2017-06-13 01:28:04 -07:00
2017-08-01 02:36:48 -07:00
const DEFAULT_POLL_INTERVAL: u64 = 1;
const DEFAULT_CONFIRMATIONS: u64 = 12;
2017-06-25 04:21:13 -07:00
/// Application config.
#[derive(Debug, PartialEq)]
2017-06-13 01:28:04 -07:00
pub struct Config {
2017-08-01 02:36:48 -07:00
pub mainnet: Node,
pub testnet: Node,
2017-06-25 04:21:13 -07:00
}
impl Default for Config {
fn default() -> Self {
Config {
mainnet: Node::default_mainnet(),
testnet: Node::default_testnet(),
}
}
}
impl From<load::Config> for Config {
fn from(config: load::Config) -> Self {
let default = Self::default();
Config {
mainnet: Node {
2017-08-01 02:36:48 -07:00
account: config.mainnet.account,
2017-06-25 04:21:13 -07:00
ipc: config.mainnet.ipc.unwrap_or(default.mainnet.ipc),
2017-08-01 02:36:48 -07:00
deploy_tx: default.mainnet.deploy_tx.with(config.mainnet.deploy_tx),
poll_interval: config.mainnet.poll_interval.map(Duration::from_secs).unwrap_or(default.mainnet.poll_interval),
required_confirmations: config.mainnet.required_confirmations.unwrap_or(default.mainnet.required_confirmations),
2017-06-25 04:21:13 -07:00
},
testnet: Node {
2017-08-01 02:36:48 -07:00
account: config.testnet.account,
2017-06-25 04:21:13 -07:00
ipc: config.testnet.ipc.unwrap_or(default.testnet.ipc),
2017-08-01 02:36:48 -07:00
deploy_tx: default.testnet.deploy_tx.with(config.testnet.deploy_tx),
poll_interval: config.testnet.poll_interval.map(Duration::from_secs).unwrap_or(default.testnet.poll_interval),
required_confirmations: config.testnet.required_confirmations.unwrap_or(default.testnet.required_confirmations),
2017-06-25 04:21:13 -07:00
}
}
}
}
impl Config {
2017-08-02 03:45:15 -07:00
pub fn load<P: AsRef<Path>>(path: P) -> Result<Config, Error> {
let mut file = fs::File::open(path).chain_err(|| "Cannot open config")?;
2017-06-25 04:21:13 -07:00
let mut buffer = String::new();
file.read_to_string(&mut buffer);
Self::load_from_str(&buffer)
}
2017-08-02 03:45:15 -07:00
fn load_from_str(s: &str) -> Result<Config, Error> {
let config: load::Config = toml::from_str(s).chain_err(|| "Cannot parse config")?;
2017-06-25 04:21:13 -07:00
Ok(config.into())
}
}
#[derive(Debug, PartialEq)]
2017-08-01 02:36:48 -07:00
pub struct Node {
2017-08-03 15:48:12 -07:00
pub account: Address,
2017-08-01 02:36:48 -07:00
pub ipc: PathBuf,
pub deploy_tx: TransactionConfig,
pub poll_interval: Duration,
pub required_confirmations: u64,
2017-06-25 04:21:13 -07:00
}
impl Node {
fn default_mainnet() -> Self {
// TODO: hardcode default mainnet ipc path
Node {
2017-08-03 15:48:12 -07:00
account: Address::default(),
2017-06-25 04:21:13 -07:00
ipc: "".into(),
2017-08-01 02:36:48 -07:00
deploy_tx: TransactionConfig::deploy_mainnet(),
poll_interval: Duration::from_secs(DEFAULT_POLL_INTERVAL),
required_confirmations: DEFAULT_CONFIRMATIONS,
2017-06-25 04:21:13 -07:00
}
}
fn default_testnet() -> Self {
// TODO: hardcode default testnet ipc path
Node {
2017-08-03 15:48:12 -07:00
account: Address::default(),
2017-06-25 04:21:13 -07:00
ipc: "".into(),
2017-08-01 02:36:48 -07:00
deploy_tx: TransactionConfig::deploy_testnet(),
poll_interval: Duration::from_secs(DEFAULT_POLL_INTERVAL),
required_confirmations: DEFAULT_CONFIRMATIONS,
}
}
}
#[derive(Debug, PartialEq)]
pub struct TransactionConfig {
pub gas: u64,
pub gas_price: u64,
pub value: u64,
}
impl TransactionConfig {
fn with(&self, loaded: Option<load::TransactionConfig>) -> Self {
let loaded_ref = loaded.as_ref();
TransactionConfig {
gas: loaded_ref.and_then(|tx| tx.gas).unwrap_or(self.gas),
gas_price: loaded_ref.and_then(|tx| tx.gas_price).unwrap_or(self.gas_price),
value: loaded_ref.and_then(|tx| tx.value).unwrap_or(self.value),
}
}
fn deploy_mainnet() -> Self {
// TODO: values
TransactionConfig {
gas: 0,
2017-08-03 15:48:12 -07:00
gas_price: 0,
2017-08-01 02:36:48 -07:00
value: 0,
}
}
fn deploy_testnet() -> Self {
// TODO: values
TransactionConfig {
2017-08-03 15:48:12 -07:00
gas: 0,
gas_price: 0,
2017-08-01 02:36:48 -07:00
value: 0,
2017-06-25 04:21:13 -07:00
}
}
}
/// Some config values may not be defined in `toml` file, but they should be specified at runtime.
/// `load` module separates `Config` representation in file with optional from the one used
/// in application.
mod load {
use std::path::PathBuf;
2017-08-03 15:48:12 -07:00
use web3::types::Address;
2017-06-25 04:21:13 -07:00
#[derive(Deserialize)]
2017-08-03 15:48:12 -07:00
#[serde(deny_unknown_fields)]
2017-06-25 04:21:13 -07:00
pub struct Config {
pub mainnet: Node,
pub testnet: Node,
}
#[derive(Deserialize)]
pub struct Node {
2017-08-03 15:48:12 -07:00
pub account: Address,
2017-06-25 04:21:13 -07:00
pub ipc: Option<PathBuf>,
2017-08-01 02:36:48 -07:00
pub deploy_tx: Option<TransactionConfig>,
pub poll_interval: Option<u64>,
pub required_confirmations: Option<u64>,
}
#[derive(Deserialize)]
pub struct TransactionConfig {
pub gas: Option<u64>,
pub gas_price: Option<u64>,
pub value: Option<u64>,
2017-06-25 04:21:13 -07:00
}
}
#[cfg(test)]
mod tests {
2017-08-01 02:36:48 -07:00
use std::time::Duration;
use super::{Config, Node, TransactionConfig};
2017-06-25 04:21:13 -07:00
#[test]
fn load_full_setup_from_str() {
let toml = r#"
[mainnet]
2017-08-03 15:48:12 -07:00
account = "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b"
2017-06-25 04:21:13 -07:00
ipc = "/mainnet.ipc"
2017-08-01 02:36:48 -07:00
poll_interval = 2
required_confirmations = 100
2017-06-25 04:21:13 -07:00
[testnet]
2017-08-01 02:36:48 -07:00
account = "0x0000000000000000000000000000000000000001"
2017-06-25 04:21:13 -07:00
ipc = "/testnet.ipc"
2017-08-01 02:36:48 -07:00
deploy_tx = { gas = 20, value = 15 }
2017-06-25 04:21:13 -07:00
"#;
2017-08-01 02:36:48 -07:00
2017-06-25 04:21:13 -07:00
let expected = Config {
mainnet: Node {
2017-08-03 15:48:12 -07:00
account: "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b".parse().unwrap(),
2017-06-25 04:21:13 -07:00
ipc: "/mainnet.ipc".into(),
2017-08-01 02:36:48 -07:00
deploy_tx: TransactionConfig {
gas: 0,
2017-08-04 08:57:09 -07:00
gas_price: 0,
2017-08-01 02:36:48 -07:00
value: 0,
},
poll_interval: Duration::from_secs(2),
required_confirmations: 100,
2017-06-25 04:21:13 -07:00
},
testnet: Node {
2017-08-03 15:48:12 -07:00
account: "0x0000000000000000000000000000000000000001".parse().unwrap(),
2017-06-25 04:21:13 -07:00
ipc: "/testnet.ipc".into(),
2017-08-01 02:36:48 -07:00
deploy_tx: TransactionConfig {
gas: 20,
2017-08-04 08:57:09 -07:00
gas_price: 0,
2017-08-01 02:36:48 -07:00
value: 15,
},
poll_interval: Duration::from_secs(1),
required_confirmations: 12,
2017-06-25 04:21:13 -07:00
}
};
2017-08-01 02:36:48 -07:00
2017-06-25 04:21:13 -07:00
let config = Config::load_from_str(toml).unwrap();
assert_eq!(expected, config);
}
#[test]
fn laod_minimal_setup_from_str() {
let toml = r#"
[mainnet]
2017-08-03 15:48:12 -07:00
account = "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b"
2017-06-25 04:21:13 -07:00
[testnet]
2017-08-03 15:48:12 -07:00
account = "0x0000000000000000000000000000000000000001"
2017-06-25 04:21:13 -07:00
"#;
2017-08-01 02:36:48 -07:00
let mut expected = Config::default();
2017-08-03 15:48:12 -07:00
expected.mainnet.account = "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b".parse().unwrap();
expected.testnet.account = "0x0000000000000000000000000000000000000001".parse().unwrap();
2017-06-25 04:21:13 -07:00
let config = Config::load_from_str(toml).unwrap();
assert_eq!(expected, config);
}
2017-06-13 01:28:04 -07:00
}