diff --git a/README.md b/README.md index 99ec030..cfa7eb4 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ and they can convert them back as well. ![withdraw](./res/withdraw.png) -### How to build +### How to build Requires `rust` and `cargo`: [installation instructions.](https://www.rust-lang.org/en-US/install.html) @@ -83,6 +83,7 @@ keystore = "/path/to/keystore" [home] account = "0x006e27b6a72e1f34c626762f3c4761547aff1421" +contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7" rpc_host = "http://localhost" rpc_port = 8545 required_confirmations = 0 @@ -91,6 +92,7 @@ default_gas_price = 1_000_000_000 # 1 GWEI [foreign] account = "0x006e27b6a72e1f34c626762f3c4761547aff1421" +contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8" rpc_host = "http://localhost" rpc_port = 9545 required_confirmations = 0 @@ -110,11 +112,12 @@ withdraw_confirm = { gas = 3000000 } #### Options -- `keystore` - path to a keystore directory with JSON keys +- `keystore` - path to a keystore directory with JSON keys #### home/foreign options - `home/foreign.account` - authority address on the home (**required**) +- `home/foreign.contract_address` - The address of the bridge contract on home/foreign chain. (**required**). - `home/foreign.rpc_host` - RPC host (**required**) - `home/foreign.rpc_port` - RPC port (**defaults to 8545**) - `home/foreign.required_confirmations` - number of confirmation required to consider transaction final on home (default: **12**) @@ -141,8 +144,6 @@ withdraw_confirm = { gas = 3000000 } ### Database file format ```toml -home_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7" -foreign_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8" checked_deposit_relay = 120 checked_withdraw_relay = 121 checked_withdraw_confirm = 121 @@ -150,8 +151,6 @@ checked_withdraw_confirm = 121 **all fields are required** -- `home_contract_address` - address of the bridge contract on home chain -- `foreign_contract_address` - address of the bridge contract on foreign chain - `checked_deposit_relay` - number of the last block for which an authority has relayed deposits to the foreign - `checked_withdraw_relay` - number of the last block for which an authority has relayed withdraws to the home - `checked_withdraw_confirm` - number of the last block for which an authority has confirmed withdraw diff --git a/bridge/src/bridge/deploy.rs b/bridge/src/bridge/deploy.rs index c7a91e0..a531420 100644 --- a/bridge/src/bridge/deploy.rs +++ b/bridge/src/bridge/deploy.rs @@ -64,64 +64,73 @@ impl Future for Deploy { fn poll(&mut self) -> Poll { loop { let _next_state = match self.state { - DeployState::CheckIfNeeded => match Database::load(&self.app.database_path).map_err(ErrorKind::from) { - Ok(database) => return Ok(Deployed::Existing(database).into()), - Err(ErrorKind::MissingFile(_e)) => { - #[cfg(feature = "deploy")] { - println!("deploy"); - let main_data = self.app.home_bridge.constructor( - self.app.config.home.contract.bin.clone().0, - self.app.config.authorities.required_signatures, - self.app.config.authorities.accounts.clone(), - self.app.config.estimated_gas_cost_of_withdraw - ); - let test_data = self.app.foreign_bridge.constructor( - self.app.config.foreign.contract.bin.clone().0, - self.app.config.authorities.required_signatures, - self.app.config.authorities.accounts.clone(), - self.app.config.estimated_gas_cost_of_withdraw - ); + DeployState::CheckIfNeeded => { + match Database::load(&self.app.database_path).map_err(ErrorKind::from) { + Ok(database) => return Ok(Deployed::Existing(database).into()), + Err(ErrorKind::MissingFile(_e)) => { + #[cfg(feature = "deploy")] { + println!("deploy"); + let main_data = self.app.home_bridge.constructor( + self.app.config.home.contract.bin.clone().0, + self.app.config.authorities.required_signatures, + self.app.config.authorities.accounts.clone(), + self.app.config.estimated_gas_cost_of_withdraw + ); + let test_data = self.app.foreign_bridge.constructor( + self.app.config.foreign.contract.bin.clone().0, + self.app.config.authorities.required_signatures, + self.app.config.authorities.accounts.clone(), + self.app.config.estimated_gas_cost_of_withdraw + ); - let main_tx = Transaction { - nonce: U256::zero(), - gas_price: self.app.config.txs.home_deploy.gas_price.into(), - gas: self.app.config.txs.home_deploy.gas.into(), - action: Action::Create, - value: U256::zero(), - data: main_data.into(), - }; + let main_tx = Transaction { + nonce: U256::zero(), + gas_price: self.app.config.txs.home_deploy.gas_price.into(), + gas: self.app.config.txs.home_deploy.gas.into(), + action: Action::Create, + value: U256::zero(), + data: main_data.into(), + }; - let test_tx = Transaction { - nonce: U256::zero(), - gas_price: self.app.config.txs.foreign_deploy.gas_price.into(), - gas: self.app.config.txs.foreign_deploy.gas.into(), - action: Action::Create, - value: U256::zero(), - data: test_data.into(), - }; + let test_tx = Transaction { + nonce: U256::zero(), + gas_price: self.app.config.txs.foreign_deploy.gas_price.into(), + gas: self.app.config.txs.foreign_deploy.gas.into(), + action: Action::Create, + value: U256::zero(), + data: test_data.into(), + }; - let main_future = api::send_transaction_with_nonce(self.app.connections.home.clone(), self.app.clone(), - self.app.config.home.clone(), main_tx, self.home_chain_id, - TransactionWithConfirmation(self.app.connections.home.clone(), self.app.config.home.poll_interval, self.app.config.home.required_confirmations)); + let main_future = api::send_transaction_with_nonce(self.app.connections.home.clone(), self.app.clone(), + self.app.config.home.clone(), main_tx, self.home_chain_id, + TransactionWithConfirmation(self.app.connections.home.clone(), self.app.config.home.poll_interval, self.app.config.home.required_confirmations)); - let test_future = api::send_transaction_with_nonce(self.app.connections.foreign.clone(), self.app.clone(), - self.app.config.foreign.clone(), test_tx, self.foreign_chain_id, - TransactionWithConfirmation(self.app.connections.foreign.clone(), self.app.config.foreign.poll_interval, self.app.config.foreign.required_confirmations)); + let test_future = api::send_transaction_with_nonce(self.app.connections.foreign.clone(), self.app.clone(), + self.app.config.foreign.clone(), test_tx, self.foreign_chain_id, + TransactionWithConfirmation(self.app.connections.foreign.clone(), self.app.config.foreign.poll_interval, self.app.config.foreign.required_confirmations)); - DeployState::Deploying(main_future.join(test_future)) - } - #[cfg(not(feature = "deploy"))] { - return Err(ErrorKind::MissingFile(_e).into()) - } - }, - Err(err) => return Err(err.into()), + DeployState::Deploying(main_future.join(test_future)) + } + #[cfg(not(feature = "deploy"))] { + return Err(ErrorKind::MissingFile(_e).into()) + } + }, + Err(err) => return Err(err.into()), + } }, #[cfg(feature = "deploy")] DeployState::Deploying(ref mut future) => { let (main_receipt, test_receipt) = try_ready!(future.poll()); + + // The `deploy` feature is being removed so this shouldn't + // matter but the following lines have been left here as a + // reminder that contract addresses are no longer stored + // within `Database`. + // + // let _ = main_receipt.contract_address.expect("contract creation receipt must have an address; qed") + // let _ = test_receipt.contract_address.expect("contract creation receipt must have an address; qed") + let database = Database { - home_contract_address: main_receipt.contract_address.expect("contract creation receipt must have an address; qed"), - foreign_contract_address: test_receipt.contract_address.expect("contract creation receipt must have an address; qed"), home_deploy: Some(main_receipt.block_number.low_u64()), foreign_deploy: Some(test_receipt.block_number.low_u64()), checked_deposit_relay: main_receipt.block_number.low_u64(), diff --git a/bridge/src/bridge/deposit_relay.rs b/bridge/src/bridge/deposit_relay.rs index dd78966..ed545ff 100644 --- a/bridge/src/bridge/deposit_relay.rs +++ b/bridge/src/bridge/deposit_relay.rs @@ -49,11 +49,11 @@ pub fn create_deposit_relay(app: Arc>, init: &Datab request_timeout: app.config.home.request_timeout, poll_interval: app.config.home.poll_interval, confirmations: app.config.home.required_confirmations, - filter: deposits_filter(&app.home_bridge, init.home_contract_address), + filter: deposits_filter(&app.home_bridge, app.config.home.contract_address), }; DepositRelay { logs: api::log_stream(app.connections.home.clone(), app.timer.clone(), logs_init), - foreign_contract: init.foreign_contract_address, + foreign_contract: app.config.foreign.contract_address, state: DepositRelayState::Wait, app, foreign_balance, @@ -92,7 +92,7 @@ impl Stream for DepositRelay { let gas = U256::from(self.app.config.txs.deposit_relay.gas); let gas_price = U256::from(*self.foreign_gas_price.read().unwrap()); let balance_required = gas * gas_price * U256::from(item.logs.len()); - + if balance_required > *foreign_balance.as_ref().unwrap() { return Err(ErrorKind::InsufficientFunds.into()) } diff --git a/bridge/src/bridge/gas_price.rs b/bridge/src/bridge/gas_price.rs index 7988635..2918997 100644 --- a/bridge/src/bridge/gas_price.rs +++ b/bridge/src/bridge/gas_price.rs @@ -165,6 +165,7 @@ mod tests { fn errored_request() { let node = Node { account: Address::new(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), request_timeout: Duration::from_secs(5), poll_interval: Duration::from_secs(1), required_confirmations: 0, @@ -208,6 +209,7 @@ mod tests { fn bad_json() { let node = Node { account: Address::new(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), request_timeout: Duration::from_secs(5), poll_interval: Duration::from_secs(1), required_confirmations: 0, @@ -251,6 +253,7 @@ mod tests { fn unexpected_json() { let node = Node { account: Address::new(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), request_timeout: Duration::from_secs(5), poll_interval: Duration::from_secs(1), required_confirmations: 0, @@ -293,6 +296,7 @@ mod tests { fn non_object_json() { let node = Node { account: Address::new(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), request_timeout: Duration::from_secs(5), poll_interval: Duration::from_secs(1), required_confirmations: 0, @@ -335,6 +339,7 @@ mod tests { fn correct_json() { let node = Node { account: Address::new(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), request_timeout: Duration::from_secs(5), poll_interval: Duration::from_secs(1), required_confirmations: 0, diff --git a/bridge/src/bridge/mod.rs b/bridge/src/bridge/mod.rs index 251b441..ef84639 100644 --- a/bridge/src/bridge/mod.rs +++ b/bridge/src/bridge/mod.rs @@ -221,6 +221,7 @@ impl<'a, T: Transport + 'a> Stream for BridgeEventStream<'a, T> { #[cfg(test)] mod tests { extern crate tempdir; + use self::tempdir::TempDir; use database::Database; use super::{Bridge, BridgeChecked}; @@ -244,6 +245,7 @@ mod tests { let _ = event_loop.run(bridge.collect()); let db = Database::load(&path).unwrap(); + assert_eq!(1, db.checked_deposit_relay); assert_eq!(0, db.checked_withdraw_confirm); assert_eq!(0, db.checked_withdraw_relay); @@ -251,13 +253,15 @@ mod tests { let bridge = Bridge { path: path.clone(), database: Database::default(), - event_stream: stream::iter_ok::<_, Error>(vec![BridgeChecked::DepositRelay(2), BridgeChecked::WithdrawConfirm(3), BridgeChecked::WithdrawRelay(2)]), + event_stream: stream::iter_ok::<_, Error>(vec![BridgeChecked::DepositRelay(2), + BridgeChecked::WithdrawConfirm(3), BridgeChecked::WithdrawRelay(2)]), }; let mut event_loop = Core::new().unwrap(); let _ = event_loop.run(bridge.collect()); let db = Database::load(&path).unwrap(); + assert_eq!(2, db.checked_deposit_relay); assert_eq!(3, db.checked_withdraw_confirm); assert_eq!(2, db.checked_withdraw_relay); diff --git a/bridge/src/bridge/withdraw_confirm.rs b/bridge/src/bridge/withdraw_confirm.rs index a287a55..53b36ef 100644 --- a/bridge/src/bridge/withdraw_confirm.rs +++ b/bridge/src/bridge/withdraw_confirm.rs @@ -44,12 +44,12 @@ pub fn create_withdraw_confirm(app: Arc>, init: &Da request_timeout: app.config.foreign.request_timeout, poll_interval: app.config.foreign.poll_interval, confirmations: app.config.foreign.required_confirmations, - filter: withdraws_filter(&app.foreign_bridge, init.foreign_contract_address.clone()), + filter: withdraws_filter(&app.foreign_bridge, app.config.foreign.contract_address.clone()), }; WithdrawConfirm { logs: api::log_stream(app.connections.foreign.clone(), app.timer.clone(), logs_init), - foreign_contract: init.foreign_contract_address, + foreign_contract: app.config.foreign.contract_address, state: WithdrawConfirmState::Wait, app, foreign_balance, diff --git a/bridge/src/bridge/withdraw_relay.rs b/bridge/src/bridge/withdraw_relay.rs index e79819b..a36505f 100644 --- a/bridge/src/bridge/withdraw_relay.rs +++ b/bridge/src/bridge/withdraw_relay.rs @@ -83,13 +83,13 @@ pub fn create_withdraw_relay(app: Arc>, init: &Data request_timeout: app.config.foreign.request_timeout, poll_interval: app.config.foreign.poll_interval, confirmations: app.config.foreign.required_confirmations, - filter: collected_signatures_filter(&app.foreign_bridge, init.foreign_contract_address), + filter: collected_signatures_filter(&app.foreign_bridge, app.config.foreign.contract_address), }; WithdrawRelay { logs: api::log_stream(app.connections.foreign.clone(), app.timer.clone(), logs_init), - home_contract: init.home_contract_address, - foreign_contract: init.foreign_contract_address, + home_contract: app.config.home.contract_address, + foreign_contract: app.config.foreign.contract_address, state: WithdrawRelayState::Wait, app, home_balance, diff --git a/bridge/src/config.rs b/bridge/src/config.rs index b092b28..5e78644 100644 --- a/bridge/src/config.rs +++ b/bridge/src/config.rs @@ -41,12 +41,12 @@ impl Config { } fn load_from_str(s: &str, allow_insecure_rpc_endpoints: bool) -> Result { - let config: load::Config = toml::from_str(s).chain_err(|| "Cannot parse config")?; + let config: parse::Config = toml::from_str(s).chain_err(|| "Cannot parse config")?; Config::from_load_struct(config, allow_insecure_rpc_endpoints) } - fn from_load_struct(config: load::Config, allow_insecure_rpc_endpoints: bool) -> Result { - let result = Config { + fn from_load_struct(config: parse::Config, allow_insecure_rpc_endpoints: bool) -> Result { + let config = Config { home: Node::from_load_struct(config.home, allow_insecure_rpc_endpoints)?, foreign: Node::from_load_struct(config.foreign, allow_insecure_rpc_endpoints)?, authorities: Authorities { @@ -60,7 +60,7 @@ impl Config { keystore: config.keystore, }; - Ok(result) + Ok(config) } } @@ -69,6 +69,7 @@ pub struct Node { pub account: Address, #[cfg(feature = "deploy")] pub contract: ContractConfig, + pub contract_address: Address, pub request_timeout: Duration, pub poll_interval: Duration, pub required_confirmations: usize, @@ -106,7 +107,7 @@ impl PartialEq for NodeInfo { } impl Node { - fn from_load_struct(node: load::Node, allow_insecure_rpc_endpoints: bool) -> Result { + fn from_load_struct(node: parse::Node, allow_insecure_rpc_endpoints: bool) -> Result { let gas_price_oracle_url = node.gas_price_oracle_url.clone(); let gas_price_speed = match node.gas_price_speed { @@ -132,7 +133,13 @@ impl Node { } } - let result = Node { + let contract_address = node.contract_address.ok_or(ErrorKind::ConfigError( + "Contract address not specified. Please define the 'contract_address' key \ + within both the '[home]' and '[foreign]' tables in the toml config file. See \ + 'https://github.com/poanetwork/poa-bridge/blob/master/README.md' \ + for more.".to_owned()))?; + + let node = Node { account: node.account, #[cfg(feature = "deploy")] contract: ContractConfig { @@ -143,6 +150,7 @@ impl Node { Bytes(read.from_hex()?) } }, + contract_address: contract_address, request_timeout: Duration::from_secs(node.request_timeout.unwrap_or(DEFAULT_TIMEOUT)), poll_interval: Duration::from_secs(node.poll_interval.unwrap_or(DEFAULT_POLL_INTERVAL)), required_confirmations: node.required_confirmations.unwrap_or(DEFAULT_CONFIRMATIONS), @@ -157,7 +165,7 @@ impl Node { concurrent_http_requests, }; - Ok(result) + Ok(node) } pub fn password(&self) -> Result { @@ -182,7 +190,7 @@ pub struct Transactions { } impl Transactions { - fn from_load_struct(cfg: load::Transactions) -> Self { + fn from_load_struct(cfg: parse::Transactions) -> Self { Transactions { #[cfg(feature = "deploy")] home_deploy: cfg.home_deploy.map(TransactionConfig::from_load_struct).unwrap_or_default(), @@ -202,7 +210,7 @@ pub struct TransactionConfig { } impl TransactionConfig { - fn from_load_struct(cfg: load::TransactionConfig) -> Self { + fn from_load_struct(cfg: parse::TransactionConfig) -> Self { TransactionConfig { gas: cfg.gas.unwrap_or_default(), gas_price: cfg.gas_price.unwrap_or_default(), @@ -260,7 +268,7 @@ impl GasPriceSpeed { /// 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 { +mod parse { use std::path::PathBuf; use web3::types::Address; @@ -282,6 +290,7 @@ mod load { pub account: Address, #[cfg(feature = "deploy")] pub contract: ContractConfig, + pub contract_address: Option
, pub request_timeout: Option, pub poll_interval: Option, pub required_confirmations: Option, @@ -348,6 +357,7 @@ keystore = "/keys" [home] account = "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b" +contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7" poll_interval = 2 required_confirmations = 100 rpc_host = "127.0.0.1" @@ -356,6 +366,7 @@ password = "password" [foreign] account = "0x0000000000000000000000000000000000000001" +contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8" rpc_host = "127.0.0.1" rpc_port = 8545 password = "password" @@ -371,6 +382,7 @@ required_signatures = 2 txs: Transactions::default(), home: Node { account: "1B68Cb0B50181FC4006Ce572cF346e596E51818b".into(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), poll_interval: Duration::from_secs(2), request_timeout: Duration::from_secs(DEFAULT_TIMEOUT), required_confirmations: 100, @@ -386,6 +398,7 @@ required_signatures = 2 }, foreign: Node { account: "0000000000000000000000000000000000000001".into(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db8".into(), poll_interval: Duration::from_secs(1), request_timeout: Duration::from_secs(DEFAULT_TIMEOUT), required_confirmations: 12, @@ -419,11 +432,13 @@ keystore = "/keys/" [home] account = "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b" +contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7" rpc_host = "" password = "password" [foreign] account = "0x0000000000000000000000000000000000000001" +contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8" rpc_host = "" password = "password" @@ -434,6 +449,7 @@ required_signatures = 2 txs: Transactions::default(), home: Node { account: "1B68Cb0B50181FC4006Ce572cF346e596E51818b".into(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), poll_interval: Duration::from_secs(1), request_timeout: Duration::from_secs(DEFAULT_TIMEOUT), required_confirmations: 12, @@ -449,6 +465,7 @@ required_signatures = 2 }, foreign: Node { account: "0000000000000000000000000000000000000001".into(), + contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db8".into(), poll_interval: Duration::from_secs(1), request_timeout: Duration::from_secs(DEFAULT_TIMEOUT), required_confirmations: 12, diff --git a/bridge/src/database.rs b/bridge/src/database.rs index 6671e4f..2d52a21 100644 --- a/bridge/src/database.rs +++ b/bridge/src/database.rs @@ -1,17 +1,13 @@ use std::path::Path; use std::{io, str, fs, fmt}; use std::io::{Read, Write}; -use web3::types::Address; use toml; use error::{Error, ResultExt, ErrorKind}; + /// Application "database". #[derive(Debug, PartialEq, Deserialize, Serialize, Default, Clone)] pub struct Database { - /// Address of home contract. - pub home_contract_address: Address, - /// Address of foreign contract. - pub foreign_contract_address: Address, /// Number of block at which home contract has been deployed. pub home_deploy: Option, /// Number of block at which foreign contract has been deployed. @@ -27,11 +23,13 @@ pub struct Database { impl str::FromStr for Database { type Err = Error; + /// Returns a new `Database` constructed from the parsed string `s`. fn from_str(s: &str) -> Result { - toml::from_str(s).chain_err(|| "Cannot parse database") + toml::from_str(s).chain_err(|| "Cannot parse database toml file/string") } } + 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")) @@ -39,11 +37,15 @@ impl fmt::Display for Database { } impl Database { - pub fn load>(path: P) -> Result { + /// Loads a user defined toml file specified by `path` and returns a new + /// `Database` containing its parsed contents. + pub fn load>(path: P) + -> Result { 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"), + 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 file"), }; let mut buffer = String::new(); @@ -51,12 +53,14 @@ impl Database { buffer.parse() } - pub fn save(&self, mut write: W) -> Result<(), Error> { - write.write_all(self.to_string().as_bytes())?; + /// Writes a serialized `Database` to a writer. + pub fn save(&self, mut writer: W) -> Result<(), Error> { + writer.write_all(self.to_string().as_bytes())?; Ok(()) } } + #[cfg(test)] mod tests { use super::Database; @@ -64,9 +68,7 @@ mod tests { #[test] fn database_to_and_from_str() { let toml = -r#"home_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7" -foreign_contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db8" -home_deploy = 100 +r#"home_deploy = 100 foreign_deploy = 101 checked_deposit_relay = 120 checked_withdraw_relay = 121 @@ -74,8 +76,6 @@ checked_withdraw_confirm = 121 "#; let expected = Database { - home_contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db7".into(), - foreign_contract_address: "49edf201c1e139282643d5e7c6fb0c7219ad1db8".into(), home_deploy: Some(100), foreign_deploy: Some(101), checked_deposit_relay: 120, @@ -86,6 +86,6 @@ checked_withdraw_confirm = 121 let database = toml.parse().unwrap(); assert_eq!(expected, database); let s = database.to_string(); - assert_eq!(s, toml); + assert!(s.contains(toml)); } } diff --git a/cli/src/main.rs b/cli/src/main.rs index 3fbf22d..c539ae6 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -143,15 +143,13 @@ fn execute(command: I, running: Arc) -> Result app, + Ok(app) => Arc::new(app), Err(e) => { warn!("Can't establish an RPC connection: {:?}", e); return Err((ERR_CANNOT_CONNECT, e).into()); }, }; - let app = Arc::new(app); - info!(target: "bridge", "Acquiring home & foreign chain ids"); let home_chain_id = event_loop.run(create_chain_id_retrieval(app.clone(), app.connections.home.clone(), app.config.home.clone())).expect("can't retrieve home chain_id"); let foreign_chain_id = event_loop.run(create_chain_id_retrieval(app.clone(), app.connections.foreign.clone(), app.config.foreign.clone())).expect("can't retrieve foreign chain_id");