Skip to content
This repository has been archived by the owner on Sep 18, 2020. It is now read-only.

validator_set (in progress) #48

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion bridge/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use web3::Transport;
use web3::transports::ipc::Ipc;
use error::{Error, ResultExt, ErrorKind};
use config::Config;
use contracts::{home, foreign};
use contracts::{home, foreign, validator};

pub struct App<T> where T: Transport {
pub config: Config,
pub database_path: PathBuf,
pub connections: Connections<T>,
pub home_bridge: home::HomeBridge,
pub foreign_bridge: foreign::ForeignBridge,
pub validators: validator::ValidatorSet,
pub timer: Timer,
}

Expand Down Expand Up @@ -58,6 +59,7 @@ impl App<Ipc> {
connections,
home_bridge: home::HomeBridge::default(),
foreign_bridge: foreign::ForeignBridge::default(),
validators: validator::ValidatorSet::default(),
timer: Timer::default(),
};
Ok(result)
Expand All @@ -72,6 +74,7 @@ impl<T: Transport> App<T> {
database_path: self.database_path.clone(),
home_bridge: home::HomeBridge::default(),
foreign_bridge: foreign::ForeignBridge::default(),
validators: validator::ValidatorSet::default(),
timer: self.timer.clone(),
}
}
Expand Down
73 changes: 73 additions & 0 deletions bridge/src/authorities.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::sync::Arc;
use futures::{Future, Poll, Async};
use tokio_timer::Timeout;
use web3::Transport;
use web3::types::{Address, Bytes, H160};

use api::{self, ApiCall};
use error::Result;
use config::AuthoritiesSource;
use contracts::validator;
use app::App;
use error::Error;

#[inline]
fn get_validator_payload(validators: &validator::ValidatorSet) -> Bytes {
validators.functions().get_validators().input().into()
}

#[inline]
fn get_validators_output(validators: &validator::ValidatorSet, output: &[u8]) -> Result<Vec<Address>> {
Ok(validators.functions().get_validators().output(output)?.into_iter().map(H160).collect())
}

pub fn fetch_authorities<T: Transport>(app: Arc<App<T>>) -> FetchAuthorities<T> {
FetchAuthorities {
app,
state: FetchAuthoritiesState::Wait,
}
}

enum FetchAuthoritiesState<T: Transport> {
Wait,
Call(Timeout<ApiCall<Bytes, T::Out>>),
}

pub struct FetchAuthorities<T: Transport> {
app: Arc<App<T>>,
state: FetchAuthoritiesState<T>,
}

impl<T: Transport> Future for FetchAuthorities<T> {
type Item = Vec<Address>;
type Error = Error;

fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let validator_address = match self.app.config.authorities.source {
AuthoritiesSource::Accounts(ref accounts) => return Ok(Async::Ready(accounts.clone())),
AuthoritiesSource::ValidatorSet(ref address) => address.clone(),
};

loop {
let next_state = match self.state {
FetchAuthoritiesState::Wait => {
let future = self.app.timer.timeout(
api::call(
&self.app.connections.foreign,
validator_address,
get_validator_payload(&self.app.validators)
), self.app.config.foreign.request_timeout
);
FetchAuthoritiesState::Call(future)
},
FetchAuthoritiesState::Call(ref mut future) => {
let bytes = try_ready!(future.poll());
let auths = get_validators_output(&self.app.validators, &bytes.0)?;
return Ok(Async::Ready(auths));
},
};

self.state = next_state;
}
}
}
96 changes: 50 additions & 46 deletions bridge/src/bridge/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use web3::Transport;
use web3::confirm::SendTransactionWithConfirmation;
use web3::types::{TransactionRequest};
use app::App;
use authorities::{fetch_authorities, FetchAuthorities};
use database::Database;
use error::{Error, ErrorKind};
use {api, ethabi};
Expand All @@ -17,6 +18,7 @@ pub enum Deployed {

enum DeployState<T: Transport + Clone> {
CheckIfNeeded,
FetchAuthorities(FetchAuthorities<T>),
Deploying(future::Join<SendTransactionWithConfirmation<T>, SendTransactionWithConfirmation<T>>),
}

Expand All @@ -41,57 +43,59 @@ impl<T: Transport + Clone> Future for Deploy<T> {
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(_)) => {
let main_data = self.app.home_bridge.constructor(
self.app.config.home.contract.bin.clone().0,
ethabi::util::pad_u32(self.app.config.authorities.required_signatures),
self.app.config.authorities.accounts.iter().map(|a| a.0.clone()).collect::<Vec<_>>()
);
let test_data = self.app.foreign_bridge.constructor(
self.app.config.foreign.contract.bin.clone().0,
ethabi::util::pad_u32(self.app.config.authorities.required_signatures),
self.app.config.authorities.accounts.iter().map(|a| a.0.clone()).collect::<Vec<_>>()
);
Err(ErrorKind::MissingFile(_)) => DeployState::FetchAuthorities(fetch_authorities(self.app.clone())),
Err(err) => return Err(err.into()),
},
DeployState::FetchAuthorities(ref mut future) => {
let authorities = try_ready!(future.poll());
let main_data = self.app.home_bridge.constructor(
self.app.config.home.contract.bin.clone().0,
ethabi::util::pad_u32(self.app.config.authorities.required_signatures),
authorities.clone().into_iter().map(|a| a.0).collect::<Vec<_>>(),
);
let test_data = self.app.foreign_bridge.constructor(
self.app.config.foreign.contract.bin.clone().0,
ethabi::util::pad_u32(self.app.config.authorities.required_signatures),
authorities.into_iter().map(|a| a.0).collect::<Vec<_>>(),
);

let main_tx_request = TransactionRequest {
from: self.app.config.home.account,
to: None,
gas: Some(self.app.config.txs.home_deploy.gas.into()),
gas_price: Some(self.app.config.txs.home_deploy.gas_price.into()),
value: None,
data: Some(main_data.into()),
nonce: None,
condition: None,
};
let main_tx_request = TransactionRequest {
from: self.app.config.home.account,
to: None,
gas: Some(self.app.config.txs.home_deploy.gas.into()),
gas_price: Some(self.app.config.txs.home_deploy.gas_price.into()),
value: None,
data: Some(main_data.into()),
nonce: None,
condition: None,
};

let test_tx_request = TransactionRequest {
from: self.app.config.foreign.account,
to: None,
gas: Some(self.app.config.txs.foreign_deploy.gas.into()),
gas_price: Some(self.app.config.txs.foreign_deploy.gas_price.into()),
value: None,
data: Some(test_data.into()),
nonce: None,
condition: None,
};
let test_tx_request = TransactionRequest {
from: self.app.config.foreign.account,
to: None,
gas: Some(self.app.config.txs.foreign_deploy.gas.into()),
gas_price: Some(self.app.config.txs.foreign_deploy.gas_price.into()),
value: None,
data: Some(test_data.into()),
nonce: None,
condition: None,
};

let main_future = api::send_transaction_with_confirmation(
self.app.connections.home.clone(),
main_tx_request,
self.app.config.home.poll_interval,
self.app.config.home.required_confirmations
);
let main_future = api::send_transaction_with_confirmation(
self.app.connections.home.clone(),
main_tx_request,
self.app.config.home.poll_interval,
self.app.config.home.required_confirmations
);

let test_future = api::send_transaction_with_confirmation(
self.app.connections.foreign.clone(),
test_tx_request,
self.app.config.foreign.poll_interval,
self.app.config.foreign.required_confirmations
);
let test_future = api::send_transaction_with_confirmation(
self.app.connections.foreign.clone(),
test_tx_request,
self.app.config.foreign.poll_interval,
self.app.config.foreign.required_confirmations
);

DeployState::Deploying(main_future.join(test_future))
},
Err(err) => return Err(err.into()),
DeployState::Deploying(main_future.join(test_future))
},
DeployState::Deploying(ref mut future) => {
let (main_receipt, test_receipt) = try_ready!(future.poll().map_err(ErrorKind::Web3));
Expand Down
59 changes: 47 additions & 12 deletions bridge/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Config {
home: Node::from_load_struct(config.home)?,
foreign: Node::from_load_struct(config.foreign)?,
authorities: Authorities {
accounts: config.authorities.accounts,
source: AuthoritiesSource::from_load_struct(config.authorities.source),
required_signatures: config.authorities.required_signatures,
},
txs: config.transactions.map(Transactions::from_load_struct).unwrap_or_default(),
Expand Down Expand Up @@ -123,10 +123,29 @@ pub struct ContractConfig {

#[derive(Debug, PartialEq, Clone)]
pub struct Authorities {
pub accounts: Vec<Address>,
pub source: AuthoritiesSource,
pub required_signatures: u32,
}

#[derive(Debug, PartialEq, Clone)]
pub enum AuthoritiesSource {
/// Authorities source defined as a list of accounts.
Accounts(Vec<Address>),
/// Address of the `ValidatorSet` contract used to fetch authorities.
///
/// https://github.com/paritytech/parity/wiki/Validator-Set
ValidatorSet(Address),
}

impl AuthoritiesSource {
fn from_load_struct(cfg: load::AuthoritiesSource) -> Self {
match cfg {
load::AuthoritiesSource::Accounts(accounts) => AuthoritiesSource::Accounts(accounts),
load::AuthoritiesSource::ValidatorSet(address) => AuthoritiesSource::ValidatorSet(address),
}
}
}

/// 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.
Expand Down Expand Up @@ -180,16 +199,26 @@ mod load {
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Authorities {
pub accounts: Vec<Address>,
pub source: AuthoritiesSource,
pub required_signatures: u32,
}

#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(tag = "type", content = "value")]
pub enum AuthoritiesSource {
#[serde(rename = "accounts")]
Accounts(Vec<Address>),
#[serde(rename = "validator_set")]
ValidatorSet(Address),
}
}

#[cfg(test)]
mod tests {
use std::time::Duration;
use rustc_hex::FromHex;
use super::{Config, Node, ContractConfig, Transactions, Authorities, TransactionConfig};
use super::{Config, Node, ContractConfig, Transactions, Authorities, TransactionConfig, AuthoritiesSource};

#[test]
fn load_full_setup_from_str() {
Expand All @@ -211,12 +240,15 @@ ipc = "/foreign.ipc"
bin = "../contracts/ForeignBridge.bin"

[authorities]
accounts = [
required_signatures = 2

[authorities.source]
type = "accounts"
value = [
"0x0000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000002",
"0x0000000000000000000000000000000000000003"
]
required_signatures = 2

[transactions]
home_deploy = { gas = 20 }
Expand Down Expand Up @@ -245,11 +277,11 @@ home_deploy = { gas = 20 }
required_confirmations: 12,
},
authorities: Authorities {
accounts: vec![
source: AuthoritiesSource::Accounts(vec![
"0x0000000000000000000000000000000000000001".parse().unwrap(),
"0x0000000000000000000000000000000000000002".parse().unwrap(),
"0x0000000000000000000000000000000000000003".parse().unwrap(),
],
]),
required_signatures: 2,
}
};
Expand Down Expand Up @@ -281,12 +313,15 @@ ipc = ""
bin = "../contracts/ForeignBridge.bin"

[authorities]
accounts = [
required_signatures = 2

[authorities.source]
type = "accounts"
value = [
"0x0000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000002",
"0x0000000000000000000000000000000000000003"
]
required_signatures = 2
"#;
let expected = Config {
txs: Transactions::default(),
Expand All @@ -311,11 +346,11 @@ required_signatures = 2
required_confirmations: 12,
},
authorities: Authorities {
accounts: vec![
source: AuthoritiesSource::Accounts(vec![
"0x0000000000000000000000000000000000000001".parse().unwrap(),
"0x0000000000000000000000000000000000000002".parse().unwrap(),
"0x0000000000000000000000000000000000000003".parse().unwrap(),
],
]),
required_signatures: 2,
}
};
Expand Down
1 change: 1 addition & 0 deletions bridge/src/contracts.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
use_contract!(home, "HomeBridge", "../contracts/HomeBridge.abi");
use_contract!(foreign, "ForeignBridge", "../contracts/ForeignBridge.abi");
use_contract!(validator, "ValidatorSet", "../contracts/ValidatorSet.abi");
3 changes: 2 additions & 1 deletion bridge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ mod macros;

pub mod api;
pub mod app;
pub mod config;
pub mod authorities;
pub mod bridge;
pub mod config;
pub mod contracts;
pub mod database;
pub mod error;
Expand Down
Loading