poa-bridge/src/config.rs

264 lines
6.6 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-10 08:55:46 -07:00
use web3::types::{Address, Bytes};
2017-08-02 03:45:15 -07:00
use error::{ResultExt, Error};
2017-08-12 07:57:07 -07:00
use bridge::{EthereumBridge, KovanBridge};
2017-08-10 08:55:46 -07:00
use {toml, ethabi};
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 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-08-10 08:55:46 -07:00
Config::from_load_struct(config)
}
fn from_load_struct(config: load::Config) -> Result<Config, Error> {
let result = Config {
mainnet: Node::from_load_struct(config.mainnet, NodeDefaults::mainnet())?,
testnet: Node::from_load_struct(config.testnet, NodeDefaults::testnet())?,
};
Ok(result)
2017-06-25 04:21:13 -07:00
}
}
#[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-10 08:55:46 -07:00
pub contract: ContractConfig,
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
}
2017-08-10 08:55:46 -07:00
struct NodeDefaults {
ipc: PathBuf,
}
impl NodeDefaults {
fn mainnet() -> Self {
NodeDefaults {
2017-06-25 04:21:13 -07:00
ipc: "".into(),
}
}
2017-08-10 08:55:46 -07:00
fn testnet() -> Self {
NodeDefaults {
2017-06-25 04:21:13 -07:00
ipc: "".into(),
2017-08-01 02:36:48 -07:00
}
}
}
2017-08-10 08:55:46 -07:00
impl Node {
fn from_load_struct(node: load::Node, defaults: NodeDefaults) -> Result<Node, Error> {
let result = Node {
account: node.account,
contract: ContractConfig {
bin: Bytes(fs::File::open(node.contract.bin)?.bytes().collect::<Result<_, _>>()?),
abi: ethabi::Contract::load(fs::File::open(node.contract.abi)?)?,
},
ipc: node.ipc.unwrap_or(defaults.ipc),
deploy_tx: TransactionConfig {
gas: node.deploy_tx.as_ref().and_then(|tx| tx.gas).unwrap_or_default(),
gas_price: node.deploy_tx.as_ref().and_then(|tx| tx.gas_price).unwrap_or_default(),
value: node.deploy_tx.as_ref().and_then(|tx| tx.value).unwrap_or_default(),
},
poll_interval: Duration::from_secs(node.poll_interval.unwrap_or(DEFAULT_POLL_INTERVAL)),
required_confirmations: node.required_confirmations.unwrap_or(DEFAULT_CONFIRMATIONS),
};
Ok(result)
}
}
2017-08-01 02:36:48 -07:00
#[derive(Debug, PartialEq)]
pub struct TransactionConfig {
pub gas: u64,
pub gas_price: u64,
pub value: u64,
}
2017-08-10 08:55:46 -07:00
#[derive(Debug, PartialEq)]
pub struct ContractConfig {
pub bin: Bytes,
pub abi: ethabi::Contract,
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-08-10 08:55:46 -07:00
pub contract: ContractConfig,
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
}
2017-08-10 08:55:46 -07:00
#[derive(Deserialize)]
pub struct ContractConfig {
pub bin: PathBuf,
pub abi: PathBuf,
}
2017-06-25 04:21:13 -07:00
}
#[cfg(test)]
mod tests {
2017-08-01 02:36:48 -07:00
use std::time::Duration;
2017-08-10 08:55:46 -07:00
use ethabi;
use super::{Config, Node, TransactionConfig, ContractConfig};
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
2017-08-10 08:55:46 -07:00
[mainnet.contract]
bin = "contracts/EthereumBridge.bin"
abi = "contracts/EthereumBridge.abi"
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-08-10 08:55:46 -07:00
[testnet.contract]
bin = "contracts/KovanBridge.bin"
abi = "contracts/KovanBridge.abi"
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-10 08:55:46 -07:00
contract: ContractConfig {
bin: include_bytes!("../contracts/EthereumBridge.bin").to_vec().into(),
abi: ethabi::Contract::load(include_bytes!("../contracts/EthereumBridge.abi") as &[u8]).unwrap(),
},
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-08-10 08:55:46 -07:00
contract: ContractConfig {
bin: include_bytes!("../contracts/KovanBridge.bin").to_vec().into(),
abi: ethabi::Contract::load(include_bytes!("../contracts/KovanBridge.abi") as &[u8]).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-08-10 08:55:46 -07:00
[mainnet.contract]
bin = "contracts/EthereumBridge.bin"
abi = "contracts/EthereumBridge.abi"
2017-06-25 04:21:13 -07:00
[testnet]
2017-08-03 15:48:12 -07:00
account = "0x0000000000000000000000000000000000000001"
2017-08-10 08:55:46 -07:00
[testnet.contract]
bin = "contracts/KovanBridge.bin"
abi = "contracts/KovanBridge.abi"
2017-06-25 04:21:13 -07:00
"#;
2017-08-10 08:55:46 -07:00
let expected = Config {
mainnet: Node {
account: "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b".parse().unwrap(),
ipc: "".into(),
contract: ContractConfig {
bin: include_bytes!("../contracts/EthereumBridge.bin").to_vec().into(),
abi: ethabi::Contract::load(include_bytes!("../contracts/EthereumBridge.abi") as &[u8]).unwrap(),
},
deploy_tx: TransactionConfig {
gas: 0,
gas_price: 0,
value: 0,
},
poll_interval: Duration::from_secs(1),
required_confirmations: 12,
},
testnet: Node {
account: "0x0000000000000000000000000000000000000001".parse().unwrap(),
ipc: "".into(),
contract: ContractConfig {
bin: include_bytes!("../contracts/KovanBridge.bin").to_vec().into(),
abi: ethabi::Contract::load(include_bytes!("../contracts/KovanBridge.abi") as &[u8]).unwrap(),
},
deploy_tx: TransactionConfig {
gas: 0,
gas_price: 0,
value: 0,
},
poll_interval: Duration::from_secs(1),
required_confirmations: 12,
}
};
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
}