2017-06-25 04:21:13 -07:00
|
|
|
use std::path::Path;
|
2017-08-04 08:57:09 -07:00
|
|
|
use std::{io, str, fs, fmt};
|
2017-06-25 04:21:13 -07:00
|
|
|
use std::io::{Read, Write};
|
2017-08-04 08:57:09 -07:00
|
|
|
use web3::types::Address;
|
2017-06-25 04:21:13 -07:00
|
|
|
use toml;
|
2017-08-04 08:57:09 -07:00
|
|
|
use error::{Error, ResultExt, ErrorKind};
|
2017-06-25 04:21:13 -07:00
|
|
|
|
|
|
|
/// Application "database".
|
|
|
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
2017-08-01 02:36:48 -07:00
|
|
|
pub struct Database {
|
2017-06-25 04:21:13 -07:00
|
|
|
pub mainnet: BlockchainState,
|
|
|
|
pub testnet: BlockchainState,
|
|
|
|
}
|
|
|
|
|
2017-08-04 08:57:09 -07:00
|
|
|
impl str::FromStr for Database {
|
|
|
|
type Err = Error;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
toml::from_str(s).chain_err(|| "Cannot parse database")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Database {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.write_str(&toml::to_string(self).expect("serialization can't fail; qed"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 02:36:48 -07:00
|
|
|
impl Database {
|
2017-08-02 03:45:15 -07:00
|
|
|
pub fn load<P: AsRef<Path>>(path: P) -> Result<Database, Error> {
|
2017-08-04 08:57:09 -07:00
|
|
|
let mut file = match fs::File::open(&path) {
|
|
|
|
Ok(file) => file,
|
|
|
|
Err(ref err) if err.kind() == io::ErrorKind::NotFound => return Err(ErrorKind::MissingFile(format!("{:?}", path.as_ref())).into()),
|
|
|
|
Err(err) => return Err(err).chain_err(|| "Cannot open database"),
|
|
|
|
};
|
|
|
|
|
2017-06-25 04:21:13 -07:00
|
|
|
let mut buffer = String::new();
|
|
|
|
file.read_to_string(&mut buffer);
|
2017-08-04 08:57:09 -07:00
|
|
|
buffer.parse()
|
2017-06-25 04:21:13 -07:00
|
|
|
}
|
|
|
|
|
2017-08-02 03:45:15 -07:00
|
|
|
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
|
|
|
|
let mut file = fs::File::open(path).chain_err(|| "Cannot save database")?;
|
2017-08-04 08:57:09 -07:00
|
|
|
file.write_all(self.to_string().as_bytes())?;
|
2017-06-25 04:21:13 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
pub struct BlockchainState {
|
|
|
|
/// Block number at which bridge has been deployed.
|
|
|
|
pub deploy_block_number: u64,
|
|
|
|
/// Bridge contract address.
|
2017-08-04 08:57:09 -07:00
|
|
|
pub bridge_contract_address: Address,
|
2017-06-25 04:21:13 -07:00
|
|
|
/// Last handled block number
|
|
|
|
pub last_block_number: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlockchainState {
|
2017-08-04 08:57:09 -07:00
|
|
|
pub fn new(block_number: u64, contract_address: Address) -> Self {
|
2017-06-25 04:21:13 -07:00
|
|
|
BlockchainState {
|
|
|
|
deploy_block_number: block_number,
|
|
|
|
bridge_contract_address: contract_address,
|
|
|
|
last_block_number: block_number,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2017-08-01 02:36:48 -07:00
|
|
|
use super::{Database, BlockchainState};
|
2017-06-25 04:21:13 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn laod_databse_from_str() {
|
|
|
|
let toml = r#"
|
|
|
|
[mainnet]
|
|
|
|
deploy_block_number = 100
|
|
|
|
bridge_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7"
|
|
|
|
last_block_number = 120
|
|
|
|
[testnet]
|
|
|
|
deploy_block_number = 101
|
|
|
|
bridge_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8"
|
|
|
|
last_block_number = 121
|
|
|
|
"#;
|
|
|
|
|
2017-08-01 02:36:48 -07:00
|
|
|
let expected = Database {
|
2017-06-25 04:21:13 -07:00
|
|
|
mainnet: BlockchainState {
|
|
|
|
deploy_block_number: 100,
|
2017-08-10 08:55:46 -07:00
|
|
|
bridge_contract_address: "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7".parse().unwrap(),
|
2017-06-25 04:21:13 -07:00
|
|
|
last_block_number: 120,
|
|
|
|
},
|
|
|
|
testnet: BlockchainState {
|
|
|
|
deploy_block_number: 101,
|
2017-08-10 08:55:46 -07:00
|
|
|
bridge_contract_address: "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8".parse().unwrap(),
|
2017-06-25 04:21:13 -07:00
|
|
|
last_block_number: 121,
|
|
|
|
},
|
|
|
|
};
|
2017-08-04 08:57:09 -07:00
|
|
|
|
|
|
|
let database = toml.parse().unwrap();
|
2017-06-25 04:21:13 -07:00
|
|
|
assert_eq!(expected, database);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn save_database_to_string() {
|
2017-08-01 02:36:48 -07:00
|
|
|
let database = Database {
|
2017-06-25 04:21:13 -07:00
|
|
|
mainnet: BlockchainState {
|
|
|
|
deploy_block_number: 100,
|
2017-08-10 08:55:46 -07:00
|
|
|
bridge_contract_address: "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7".parse().unwrap(),
|
2017-06-25 04:21:13 -07:00
|
|
|
last_block_number: 120,
|
|
|
|
},
|
|
|
|
testnet: BlockchainState {
|
|
|
|
deploy_block_number: 101,
|
2017-08-10 08:55:46 -07:00
|
|
|
bridge_contract_address: "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8".parse().unwrap(),
|
2017-06-25 04:21:13 -07:00
|
|
|
last_block_number: 121,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
let expected = r#"[mainnet]
|
|
|
|
deploy_block_number = 100
|
|
|
|
bridge_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7"
|
|
|
|
last_block_number = 120
|
|
|
|
|
|
|
|
[testnet]
|
|
|
|
deploy_block_number = 101
|
|
|
|
bridge_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8"
|
|
|
|
last_block_number = 121
|
|
|
|
"#;
|
|
|
|
|
2017-08-04 08:57:09 -07:00
|
|
|
let raw = database.to_string();
|
2017-06-25 04:21:13 -07:00
|
|
|
assert_eq!(expected, &raw);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|