Skip to content

Commit

Permalink
Move bridge contact addresses to primary configuration file.
Browse files Browse the repository at this point in the history
* Allow creation of `Database` from either a stored database configuration
  containing a `home_contract_address` and `foreign_contract_address` or a
  user defined configuration without contract address fields.
  * User defined database configuration files are parsed through the
    `database::parsed::UserDefinedDatabase` struct.
  * Stored database configuration files are parsed through the
    `database::parsed::StoredDatabase` struct.
* Deprecate `Database::save` in favor of `Deprecate::store`.
* Add the `Database::load_user_defined` method to handle creation of a
  `Database` from a user defined configuration containing no contract
  addresses.
* Deprecate `Database::load` in favor of `Database::load_stored`.
  `Database::load_stored` will create a new `Database` from a stored database
  configuration file *containing* contract addresses.
* Remove the `FromStr` impl for `Database`.
* Rename the `config::load` module to `parse`.
* Update tests.
  • Loading branch information
c0gent committed Jun 19, 2018
1 parent 69474ce commit 6af4a1d
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 78 deletions.
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -83,6 +83,7 @@ keystore = "/path/to/keystore"

[home]
account = "0x006e27b6a72e1f34c626762f3c4761547aff1421"
contract_address = "0x49edf201c1e139282643d5e7c6fb0c7219ad1db7"
rpc_host = "http://localhost"
rpc_port = 8545
required_confirmations = 0
Expand All @@ -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
Expand All @@ -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** unless the configuration is being used in a deploy build [FIXME: clarify this description]).
- `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**)
Expand All @@ -141,17 +144,13 @@ 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
```

**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
104 changes: 58 additions & 46 deletions bridge/src/bridge/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum Deployed {
Existing(Database),
}

// FIXME: Needs documentation. What do these states signify?
#[cfg(feature = "deploy")]
enum DeployState<T: Transport + Clone> {
CheckIfNeeded,
Expand Down Expand Up @@ -64,61 +65,72 @@ impl<T: Transport + Clone> Future for Deploy<T> {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
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 => {
let db = Database::load_user_defined(
&self.app.database_path,
self.app.config.home.contract_address.expect("Home contract \
address must be specified within config toml."),
self.app.config.foreign.contract_address.expect("Foreign contract \
address must be specified within config toml."))
.map_err(ErrorKind::from);

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(),
};
match db {
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 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_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_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_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_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 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));

DeployState::Deploying(main_future.join(test_future))
}
#[cfg(not(feature = "deploy"))] {
return Err(ErrorKind::MissingFile(_e).into())
}
},
Err(err) => return Err(err.into()),
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()),
}
},
#[cfg(feature = "deploy")]
DeployState::Deploying(ref mut future) => {
let (main_receipt, test_receipt) = try_ready!(future.poll());

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"),
Expand Down
5 changes: 5 additions & 0 deletions bridge/src/bridge/gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ mod tests {
fn errored_request() {
let node = Node {
account: Address::new(),
contract_address: Some("49edf201c1e139282643d5e7c6fb0c7219ad1db7".into()),
request_timeout: Duration::from_secs(5),
poll_interval: Duration::from_secs(1),
required_confirmations: 0,
Expand Down Expand Up @@ -208,6 +209,7 @@ mod tests {
fn bad_json() {
let node = Node {
account: Address::new(),
contract_address: Some("49edf201c1e139282643d5e7c6fb0c7219ad1db7".into()),
request_timeout: Duration::from_secs(5),
poll_interval: Duration::from_secs(1),
required_confirmations: 0,
Expand Down Expand Up @@ -251,6 +253,7 @@ mod tests {
fn unexpected_json() {
let node = Node {
account: Address::new(),
contract_address: Some("49edf201c1e139282643d5e7c6fb0c7219ad1db7".into()),
request_timeout: Duration::from_secs(5),
poll_interval: Duration::from_secs(1),
required_confirmations: 0,
Expand Down Expand Up @@ -293,6 +296,7 @@ mod tests {
fn non_object_json() {
let node = Node {
account: Address::new(),
contract_address: Some("49edf201c1e139282643d5e7c6fb0c7219ad1db7".into()),
request_timeout: Duration::from_secs(5),
poll_interval: Duration::from_secs(1),
required_confirmations: 0,
Expand Down Expand Up @@ -335,6 +339,7 @@ mod tests {
fn correct_json() {
let node = Node {
account: Address::new(),
contract_address: Some("49edf201c1e139282643d5e7c6fb0c7219ad1db7".into()),
request_timeout: Duration::from_secs(5),
poll_interval: Duration::from_secs(1),
required_confirmations: 0,
Expand Down
10 changes: 7 additions & 3 deletions bridge/src/bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -243,21 +244,24 @@ mod tests {
let mut event_loop = Core::new().unwrap();
let _ = event_loop.run(bridge.collect());

let db = Database::load(&path).unwrap();
let db = Database::load_saved(&path).unwrap();

assert_eq!(1, db.checked_deposit_relay);
assert_eq!(0, db.checked_withdraw_confirm);
assert_eq!(0, db.checked_withdraw_relay);

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();
let db = Database::load_saved(&path).unwrap();

assert_eq!(2, db.checked_deposit_relay);
assert_eq!(3, db.checked_withdraw_confirm);
assert_eq!(2, db.checked_withdraw_relay);
Expand Down
Loading

0 comments on commit 6af4a1d

Please sign in to comment.