Fixed build errors in tests.

This commit is contained in:
Peter van Nostrand 2018-06-19 12:55:39 -04:00
parent 8fd93a679c
commit 9415b7356c
14 changed files with 276 additions and 287 deletions

View File

@ -22,6 +22,7 @@ fn check_rustc_version() {
fn main() {
check_rustc_version();
/*
// rerun build script if bridge contract has changed.
// without this cargo doesn't since the bridge contract
// is outside the crate directories
@ -53,4 +54,5 @@ fn main() {
}
}
}
*/
}

View File

@ -1,3 +1,4 @@
/*
use std::sync::Arc;
use futures::{Future, Poll};
#[cfg(feature = "deploy")]
@ -126,7 +127,7 @@ impl<T: Transport + Clone> Future for Deploy<T> {
foreign_deploy: Some(test_receipt.block_number.low_u64()),
checked_deposit_relay: main_receipt.block_number.low_u64(),
checked_deposit_confirm: main_receipt.block_number.low_u64(),
checked_withdraw_relay: test_receipt.block_number.low_u64(),
checked_withdraw_relay: test_receipt.block_number.low_u64(),
checked_withdraw_confirm: test_receipt.block_number.low_u64(),
};
return Ok(Deployed::New(database).into())
@ -138,3 +139,4 @@ impl<T: Transport + Clone> Future for Deploy<T> {
}
}
}
/*

View File

@ -46,8 +46,8 @@ enum State<T: Transport> {
// Waiting for all calls to the Home contract's `submitSignature()`
// function to finish.
WaitingOnSubmitSignatures {
future: SubmitSignaturesFuture<T>,
last_block_checked: u64,
future: SubmitSignaturesFuture<T>,
last_block_checked: u64,
},
// All calls to the Home Contract's `submitSignature()` function
// have finished. Yields the block number for the last block
@ -73,19 +73,17 @@ pub fn create_deposit_confirm<T: Transport + Clone>(
home_gas_price: Arc<RwLock<u64>>
) -> DepositConfirm<T>
{
let home_config = &app.config.home;
let deposit_event_filter = create_deposit_filter(
let deposit_log_filter = create_deposit_filter(
&app.home_bridge,
init.home_contract_address
);
let logs_init = LogStreamInit {
after: init.checked_deposit_confirm,
request_timeout: home_config.request_timeout,
poll_interval: home_config.poll_interval,
confirmations: home_config.required_confirmations,
filter: deposit_event_filter,
request_timeout: app.config.home.request_timeout,
poll_interval: app.config.home.poll_interval,
confirmations: app.config.home.required_confirmations,
filter: deposit_log_filter,
};
let deposit_log_stream = log_stream(
@ -111,8 +109,8 @@ impl<T: Transport> Stream for DepositConfirm<T> {
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let app = &self.app;
let home_config = app.config.home.clone();
let home_conn = app.connections.home;
let home_config = &app.config.home;
let home_conn = &app.connections.home;
let home_contract = &app.home_bridge;
let home_contract_address = self.home_contract_address;
let home_chain_id = self.home_chain_id;
@ -140,17 +138,17 @@ impl<T: Transport> Stream for DepositConfirm<T> {
let n_new_deposits = logs.len();
info!("got {} new deposits to sign", n_new_deposits);
let mut messages: Vec<Vec<u8>> = logs.into_iter()
let mut messages = logs.into_iter()
.map(|log| {
info!(
"deposit is ready for signature submission. tx hash {}",
log.transaction_hash.unwrap()
);
MessageToMainnet::from_home_deposit_log(log)
MessageToMainnet::from_deposit_log(log)
.map(|msg| msg.to_bytes())
})
.collect()?;
.collect::<Result<Vec<Vec<u8>>, Error>>()?;
let signatures = messages.iter()
.map(|message| {
@ -189,11 +187,11 @@ impl<T: Transport> Stream for DepositConfirm<T> {
send_transaction_with_nonce(
home_conn.clone(),
app.clone(),
home_config,
home_config.clone(),
tx,
home_chain_id,
SendRawTransaction(home_conn.clone()),
)
SendRawTransaction(home_conn.clone())
)
})
.collect_vec();

View File

@ -14,9 +14,9 @@ use error::Error;
const CACHE_TIMEOUT_DURATION: Duration = Duration::from_secs(5 * 60);
enum State<F> {
Initial,
WaitingForResponse(Timeout<F>),
Yield(Option<u64>),
Initial,
WaitingForResponse(Timeout<F>),
Yield(Option<u64>),
}
pub trait Retriever {
@ -41,14 +41,14 @@ impl<C, B> Retriever for Client<C, B> where C: Connect, B: Stream<Item = Chunk,
pub type StandardGasPriceStream = GasPriceStream<Box<Future<Item = Chunk, Error = Error>>, Client<HttpsConnector<HttpConnector>>, Chunk>;
pub struct GasPriceStream<F, R, I> where I: AsRef<[u8]>, F: Future<Item = I, Error = Error>, R: Retriever<Future = F, Item = F::Item> {
state: State<F>,
retriever: R,
uri: Uri,
speed: GasPriceSpeed,
request_timer: Timer,
interval: Interval,
last_price: u64,
request_timeout: Duration,
state: State<F>,
retriever: R,
uri: Uri,
speed: GasPriceSpeed,
request_timer: Timer,
interval: Interval,
last_price: u64,
request_timeout: Duration,
}
impl StandardGasPriceStream {
@ -61,44 +61,44 @@ impl StandardGasPriceStream {
}
impl<F, R, I> GasPriceStream<F, R, I> where I: AsRef<[u8]>, F: Future<Item = I, Error = Error>, R: Retriever<Future = F, Item = F::Item> {
pub fn new_with_retriever(node: &Node, retriever: R, timer: &Timer) -> Self {
let uri: Uri = node.gas_price_oracle_url.clone().unwrap().parse().unwrap();
pub fn new_with_retriever(node: &Node, retriever: R, timer: &Timer) -> Self {
let uri: Uri = node.gas_price_oracle_url.clone().unwrap().parse().unwrap();
GasPriceStream {
state: State::Initial,
retriever,
uri,
speed: node.gas_price_speed,
request_timer: timer.clone(),
interval: timer.interval_at(Instant::now(), CACHE_TIMEOUT_DURATION),
last_price: node.default_gas_price,
request_timeout: node.gas_price_timeout,
}
}
GasPriceStream {
state: State::Initial,
retriever,
uri,
speed: node.gas_price_speed,
request_timer: timer.clone(),
interval: timer.interval_at(Instant::now(), CACHE_TIMEOUT_DURATION),
last_price: node.default_gas_price,
request_timeout: node.gas_price_timeout,
}
}
}
impl<F, R, I> Stream for GasPriceStream<F, R, I> where I: AsRef<[u8]>, F: Future<Item = I, Error = Error>, R: Retriever<Future = F, Item = F::Item> {
type Item = u64;
type Error = Error;
type Item = u64;
type Error = Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
loop {
let next_state = match self.state {
State::Initial => {
let _ = try_stream!(self.interval.poll());
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
loop {
let next_state = match self.state {
State::Initial => {
let _ = try_stream!(self.interval.poll());
let request = self.retriever.retrieve(&self.uri);
let request = self.retriever.retrieve(&self.uri);
let request_future = self.request_timer
.timeout(request, self.request_timeout);
let request_future = self.request_timer
.timeout(request, self.request_timeout);
State::WaitingForResponse(request_future)
},
State::WaitingForResponse(ref mut request_future) => {
match request_future.poll() {
Ok(Async::NotReady) => return Ok(Async::NotReady),
Ok(Async::Ready(chunk)) => {
match json::from_slice::<HashMap<String, json::Value>>(chunk.as_ref()) {
State::WaitingForResponse(request_future)
},
State::WaitingForResponse(ref mut request_future) => {
match request_future.poll() {
Ok(Async::NotReady) => return Ok(Async::NotReady),
Ok(Async::Ready(chunk)) => {
match json::from_slice::<HashMap<String, json::Value>>(chunk.as_ref()) {
Ok(json_obj) => {
match json_obj.get(self.speed.as_str()) {
Some(json::Value::Number(price)) => State::Yield(Some((price.as_f64().unwrap() * 1_000_000_000.0).trunc() as u64)),
@ -113,14 +113,14 @@ impl<F, R, I> Stream for GasPriceStream<F, R, I> where I: AsRef<[u8]>, F: Future
State::Yield(Some(self.last_price))
}
}
},
Err(e) => {
error!("Error while fetching gas price: {:?}", e);
},
Err(e) => {
error!("Error while fetching gas price: {:?}", e);
State::Yield(Some(self.last_price))
},
}
},
State::Yield(ref mut opt) => match opt.take() {
},
}
},
State::Yield(ref mut opt) => match opt.take() {
None => State::Initial,
Some(price) => {
if price != self.last_price {
@ -128,13 +128,13 @@ impl<F, R, I> Stream for GasPriceStream<F, R, I> where I: AsRef<[u8]>, F: Future
self.last_price = price;
}
return Ok(Async::Ready(Some(price)))
},
},
}
};
};
self.state = next_state;
}
}
self.state = next_state;
}
}
}
#[cfg(test)]
@ -143,7 +143,7 @@ mod tests {
use super::*;
use error::{Error, ErrorKind};
use futures::{Async, future::{err, ok, FutureResult}};
use config::{Node, NodeInfo, DEFAULT_CONCURRENCY};
use config::{ContractConfig, DEFAULT_CONCURRENCY, Node, NodeInfo};
use tokio_timer::Timer;
use std::time::Duration;
use std::path::PathBuf;
@ -165,6 +165,7 @@ mod tests {
fn errored_request() {
let node = Node {
account: Address::new(),
contract: ContractConfig { bin: vec![].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: ContractConfig { bin: vec![].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: ContractConfig { bin: vec![].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: ContractConfig { bin: vec![].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: ContractConfig { bin: vec![].into() },
request_timeout: Duration::from_secs(5),
poll_interval: Duration::from_secs(1),
required_confirmations: 0,
@ -363,4 +368,3 @@ mod tests {
}
}

View File

@ -1,4 +1,3 @@
mod deploy;
mod balance;
mod chain_id;
pub mod nonce;
@ -18,7 +17,6 @@ use database::Database;
use error::{Error, ErrorKind};
use tokio_core::reactor::Handle;
pub use self::deploy::{Deploy, Deployed, create_deploy};
pub use self::balance::{BalanceCheck, create_balance_check};
pub use self::chain_id::{ChainIdRetrieval, create_chain_id_retrieval};
pub use self::deposit_confirm::create_deposit_confirm;
@ -27,9 +25,9 @@ pub use self::withdraw_relay::create_withdraw_relay;
pub use self::gas_price::StandardGasPriceStream;
/// Last block checked by the bridge components.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
pub enum BridgeChecked {
DepositConfirm(u64),
DepositConfirm(u64),
DepositRelay(u64),
WithdrawRelay(u64),
}
@ -251,7 +249,7 @@ mod tests {
let bridge = Bridge {
path: path.clone(),
database: Database::default(),
event_stream: stream::iter_ok::<_, Error>(vec![BridgeChecked::DepositConfirm(1), BridgeChecked::DepositRelay(2), BridgeChecked::WithdrawConfirm(3)]),
event_stream: stream::iter_ok::<_, Error>(vec![BridgeChecked::DepositConfirm(1), BridgeChecked::DepositRelay(2), BridgeChecked::WithdrawRelay(3)]),
};
let mut event_loop = Core::new().unwrap();

View File

@ -20,7 +20,7 @@ use util::web3_filter;
// A future representing all currently open calls to the Home
// contract's `withdraw()` function.
type WithdrawsFuture<T: Transport> =
Collect<FuturesUnordered<NonceCheck<T, SendRawTransaction<T>>>>;
Collect<FuturesUnordered<NonceCheck<T, SendRawTransaction<T>>>>;
fn create_withdraw_filter(foreign: &ForeignBridge, address: Address) -> FilterBuilder {
let filter = foreign.events().withdraw().create_filter();
@ -28,37 +28,41 @@ fn create_withdraw_filter(foreign: &ForeignBridge, address: Address) -> FilterBu
}
fn create_withdraw_payload(
foreign: &ForeignBridge,
home: &HomeBridge,
withdraw_event_log: &Log
foreign: &ForeignBridge,
home: &HomeBridge,
withdraw_event_log: Log
) -> Vec<u8>
{
let raw_log = RawLog {
topics: withdraw_event_log.topics,
data: withdraw_event_log.data.0
};
let raw_log = RawLog {
topics: withdraw_event_log.topics,
data: withdraw_event_log.data.0
};
let parsed = foreign.events().withdraw()
.parse_log(raw_log)
.unwrap();
let parsed = foreign.events().withdraw()
.parse_log(raw_log)
.unwrap();
home.functions().withdraw()
.input(parsed.recipient, parsed.value, parsed.transaction_hash)
let tx_hash = withdraw_event_log.transaction_hash
.expect("Withdraw event does not contain a `transaction_hash`")
.0;
home.functions().withdraw()
.input(parsed.recipient, parsed.value, tx_hash)
}
// Represents each possible state for the `WithdrawRelay`.
enum State<T: Transport> {
// Monitoring the Foreign chain for new `Withdraw` events.
Initial,
// Waiting for all calls to the Home Contract's `withdraw()`
// function to finish.
WaitingOnWithdraws {
future: WithdrawsFuture<T>,
// Monitoring the Foreign chain for new `Withdraw` events.
Initial,
// Waiting for all calls to the Home Contract's `withdraw()`
// function to finish.
WaitingOnWithdraws {
future: WithdrawsFuture<T>,
last_block_checked: u64,
},
},
// All calls to the Home Contract's `withdraw()` function have
// finished. Yields the block number for the last block checked
// for `Withdraw` events on the Foreign chain.
// finished. Yields the block number for the last block checked
// for `Withdraw` events on the Foreign chain.
Yield(Option<u64>),
}
@ -66,49 +70,44 @@ pub struct WithdrawRelay<T: Transport> {
app: Arc<App<T>>,
logs: LogStream<T>,
state: State<T>,
foreign_contract_address: Address,
home_contract_address: Address,
home_balance: Arc<RwLock<Option<U256>>>,
home_balance: Arc<RwLock<Option<U256>>>,
home_chain_id: u64,
home_gas_price: Arc<RwLock<u64>>,
}
pub fn create_withdraw_relay<T: Transport>(
app: Arc<App<T>>,
init: &Database,
home_balance: Arc<RwLock<Option<U256>>>,
home_chain_id: u64,
home_gas_price: Arc<RwLock<u64>>,
app: Arc<App<T>>,
init: &Database,
home_balance: Arc<RwLock<Option<U256>>>,
home_chain_id: u64,
home_gas_price: Arc<RwLock<u64>>,
) -> WithdrawRelay<T>
{
let home_contract_address = init.home_contract_address;
let foreign_contract_address = init.foreign_contract_address;
let withdraw_event_filter = create_withdraw_filter(
&app.foreign_bridge,
foreign_contract_address
);
let withdraw_event_filter = create_withdraw_filter(
&app.foreign_bridge,
init.foreign_contract_address
);
let logs_init = LogStreamInit {
after: init.checked_withdraw_relay,
request_timeout: app.config.foreign.request_timeout,
poll_interval: app.config.foreign.poll_interval,
confirmations: app.config.foreign.required_confirmations,
filter: withdraw_event_filter,
};
let logs_init = LogStreamInit {
after: init.checked_withdraw_relay,
request_timeout: app.config.foreign.request_timeout,
poll_interval: app.config.foreign.poll_interval,
confirmations: app.config.foreign.required_confirmations,
filter: withdraw_event_filter,
};
let withdraw_log_stream = log_stream(
app.connections.foreign.clone(),
app.timer.clone(),
logs_init
);
let withdraw_log_stream = log_stream(
app.connections.foreign.clone(),
app.timer.clone(),
logs_init
);
WithdrawRelay {
WithdrawRelay {
app,
logs: withdraw_log_stream,
logs: withdraw_log_stream,
state: State::Initial,
foreign_contract_address,
home_contract_address,
home_contract_address: init.home_contract_address,
home_balance,
home_chain_id,
home_gas_price,
@ -120,79 +119,93 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
type Error = Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let app = &self.app;
let home_config = app.config.home;
let home_conn = app.connections.home;
let home_contract = &app.home_bridge;
let foreign_contract = &app.foreign_bridge;
let gas_per_withdraw_call = self.app.config.txs.withdraw_relay.gas.into();
let home_gas_price = U256::from(*self.home_gas_price.read().unwrap());
let app = &self.app;
let home_config = &app.config.home;
let home_conn = &app.connections.home;
let home_contract = &app.home_bridge;
let foreign_contract = &app.foreign_bridge;
let gas_per_withdraw = self.app.config.txs.withdraw_relay.gas.into();
loop {
loop {
let next_state = match self.state {
State::Initial => {
State::Initial => {
let home_balance = self.home_balance.read().unwrap();
if home_balance.is_none() {
warn!("home contract balance is unknown");
return Ok(Async::NotReady);
}
let LogStreamItem { to: last_block_checked, logs, .. } = try_stream!(
self.logs.poll().map_err(|e| {
let context = "polling Foreign contract for Withdraw event logs";
ErrorKind::ContextualizedError(Box::new(e), context)
})
);
self.logs.poll().map_err(|e| {
let context = "polling Foreign contract for Withdraw event logs";
ErrorKind::ContextualizedError(Box::new(e), context)
})
);
info!("found {} new Withdraw events", logs.len());
let withdraws = logs.iter()
.map(|log| {
let payload = create_withdraw_payload(
foreign_contract,
home_contract,
log
);
let n_withdraws: U256 = logs.len().into();
info!("found {} new Withdraw events", n_withdraws);
let tx = Transaction {
gas: gas_per_withdraw_call,
gas_price: home_gas_price,
value: U256::zero(),
data: payload,
nonce: U256::zero(),
action: Action::Call(self.home_contract_address),
};
send_transaction_with_nonce(
home_conn.clone(),
app.clone(),
home_config.clone(),
tx,
self.home_chain_id,
SendRawTransaction(home_conn.clone()),
)
})
.collect_vec();
let gas_price = U256::from(*self.home_gas_price.read().unwrap());
let balance_required = n_withdraws * gas_per_withdraw * gas_price;
State::WaitingOnWithdraws {
future: futures_unordered(withdraws).collect(),
last_block_checked,
}
},
State::WaitingOnWithdraws { ref mut future, last_block_checked } => {
if balance_required > *home_balance.as_ref().unwrap() {
return Err(ErrorKind::InsufficientFunds.into());
}
let withdraws = logs.into_iter()
.map(|log| {
let payload = create_withdraw_payload(
foreign_contract,
home_contract,
log
);
let tx = Transaction {
gas: gas_per_withdraw,
gas_price,
value: U256::zero(),
data: payload,
nonce: U256::zero(),
action: Action::Call(self.home_contract_address),
};
send_transaction_with_nonce(
home_conn.clone(),
app.clone(),
home_config.clone(),
tx,
self.home_chain_id,
SendRawTransaction(home_conn.clone()),
)
})
.collect_vec();
State::WaitingOnWithdraws {
future: futures_unordered(withdraws).collect(),
last_block_checked,
}
},
State::WaitingOnWithdraws { ref mut future, last_block_checked } => {
let _ = try_ready!(
future.poll().map_err(|e| {
let context = "sending withdraws to home";
ErrorKind::ContextualizedError(Box::new(e), context)
})
);
future.poll().map_err(|e| {
let context = "sending withdraws to home";
ErrorKind::ContextualizedError(Box::new(e), context)
})
);
info!("finished relaying withdraws to Home");
State::Yield(Some(last_block_checked))
},
State::Yield(ref mut block) => match block.take() {
Some(block) => {
let checked = BridgeChecked::WithdrawRelay(block);
return Ok(Async::Ready(Some(checked)));
},
None => State::Initial,
},
};
self.state = next_state;
}
}
State::Yield(ref mut block) => match block.take() {
Some(block) => {
let checked = BridgeChecked::WithdrawRelay(block);
return Ok(Async::Ready(Some(checked)));
},
None => State::Initial,
},
};
self.state = next_state;
}
}
}

View File

@ -88,7 +88,7 @@ use web3::types::U256;
#[derive(Debug, Clone)]
pub struct NodeInfo {
pub nonce: Arc<RwLock<U256>>,
pub nonce: Arc<RwLock<U256>>,
}
impl Default for NodeInfo {
@ -188,7 +188,7 @@ impl Transactions {
home_deploy: cfg.home_deploy.map(TransactionConfig::from_load_struct).unwrap_or_default(),
#[cfg(feature = "deploy")]
foreign_deploy: cfg.foreign_deploy.map(TransactionConfig::from_load_struct).unwrap_or_default(),
deposit_confirm: cfg.deposit_relay.map(TransactionConfig::from_load_struct).unwrap_or_default(),
deposit_confirm: cfg.deposit_confirm.map(TransactionConfig::from_load_struct).unwrap_or_default(),
deposit_relay: cfg.deposit_relay.map(TransactionConfig::from_load_struct).unwrap_or_default(),
withdraw_relay: cfg.withdraw_relay.map(TransactionConfig::from_load_struct).unwrap_or_default(),
}
@ -223,10 +223,10 @@ pub struct Authorities {
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum GasPriceSpeed {
Instant,
Fast,
Standard,
Slow,
Instant,
Fast,
Standard,
Slow,
}
impl FromStr for GasPriceSpeed {
@ -329,19 +329,16 @@ mod load {
#[cfg(test)]
mod tests {
use std::time::Duration;
#[cfg(feature = "deploy")]
use rustc_hex::FromHex;
use super::{Config, Node, Transactions, Authorities};
#[cfg(feature = "deploy")]
use super::ContractConfig;
#[cfg(feature = "deploy")]
use super::TransactionConfig;
use super::{DEFAULT_TIMEOUT, DEFAULT_GAS_PRICE_SPEED, DEFAULT_GAS_PRICE_TIMEOUT_SECS, DEFAULT_GAS_PRICE_WEI};
use super::{DEFAULT_CONCURRENCY, DEFAULT_TIMEOUT, DEFAULT_GAS_PRICE_SPEED, DEFAULT_GAS_PRICE_TIMEOUT_SECS, DEFAULT_GAS_PRICE_WEI};
#[test]
fn load_full_setup_from_str() {
let toml = r#"
keystore = "/keys"
estimated_gas_cost_of_withdraw = 0
[home]
account = "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b"
@ -368,6 +365,7 @@ required_signatures = 2
txs: Transactions::default(),
home: Node {
account: "1B68Cb0B50181FC4006Ce572cF346e596E51818b".into(),
contract: ContractConfig { bin: vec![].into() },
poll_interval: Duration::from_secs(2),
request_timeout: Duration::from_secs(DEFAULT_TIMEOUT),
required_confirmations: 100,
@ -383,6 +381,7 @@ required_signatures = 2
},
foreign: Node {
account: "0000000000000000000000000000000000000001".into(),
contract: ContractConfig { bin: vec![].into() },
poll_interval: Duration::from_secs(1),
request_timeout: Duration::from_secs(DEFAULT_TIMEOUT),
required_confirmations: 12,
@ -403,6 +402,7 @@ required_signatures = 2
required_signatures: 2,
},
keystore: "/keys/".into(),
estimated_gas_cost_of_withdraw: 0,
};
let config = Config::load_from_str(toml, true).unwrap();
@ -413,6 +413,7 @@ required_signatures = 2
fn load_minimal_setup_from_str() {
let toml = r#"
keystore = "/keys/"
estimated_gas_cost_of_withdraw = 0
[home]
account = "0x1B68Cb0B50181FC4006Ce572cF346e596E51818b"
@ -431,6 +432,7 @@ required_signatures = 2
txs: Transactions::default(),
home: Node {
account: "1B68Cb0B50181FC4006Ce572cF346e596E51818b".into(),
contract: ContractConfig { bin: vec![].into() },
poll_interval: Duration::from_secs(1),
request_timeout: Duration::from_secs(DEFAULT_TIMEOUT),
required_confirmations: 12,
@ -446,6 +448,7 @@ required_signatures = 2
},
foreign: Node {
account: "0000000000000000000000000000000000000001".into(),
contract: ContractConfig { bin: vec![].into() },
poll_interval: Duration::from_secs(1),
request_timeout: Duration::from_secs(DEFAULT_TIMEOUT),
required_confirmations: 12,
@ -466,6 +469,7 @@ required_signatures = 2
required_signatures: 2,
},
keystore: "/keys/".into(),
estimated_gas_cost_of_withdraw: 0,
};
let config = Config::load_from_str(toml, true).unwrap();

View File

@ -1,4 +1,8 @@
#![recursion_limit="128"]
// Do not throw warnings when type aliases (that are generic over
// some type/types) are annotated with trait bounds. The compiler does
// not enforce thses bounds, but they aid in readability.
#![allow(type_alias_bounds)]
#[macro_use]
extern crate futures;
extern crate serde;

View File

@ -1,5 +1,5 @@
use ethereum_types::{Address, U256, H256};
use contracts::{foreign::events::Withdraw, home::events::Deposit};
use contracts::home::events::Deposit;
use web3::types::Log;
use ethabi::{self, RawLog};
use error::Error;
@ -12,11 +12,9 @@ pub struct MessageToMainnet {
pub recipient: Address,
pub value: U256,
pub sidenet_transaction_hash: H256,
// pub mainnet_gas_price: U256,
}
/// length of a `MessageToMainnet.to_bytes()` in bytes
// pub const MESSAGE_LENGTH: usize = 116;
pub const MESSAGE_LENGTH: usize = 84;
impl MessageToMainnet {
@ -28,35 +26,17 @@ impl MessageToMainnet {
recipient: bytes[0..20].into(),
value: (&bytes[20..52]).into(),
sidenet_transaction_hash: bytes[52..84].into(),
// mainnet_gas_price: (&bytes[84..MESSAGE_LENGTH]).into(),
}
}
/*
/// construct a message from a `Withdraw` event that was logged on `foreign`
pub fn from_log(web3_log: Log) -> Result<Self, Error> {
let ethabi_raw_log = ethabi::RawLog {
topics: web3_log.topics,
data: web3_log.data.0,
};
let withdraw_log = Withdraw::default().parse_log(ethabi_raw_log)?;
let hash = web3_log.transaction_hash.ok_or_else(|| "`log` must be mined and contain `transaction_hash`")?;
Ok(Self {
recipient: withdraw_log.recipient,
value: withdraw_log.value,
sidenet_transaction_hash: hash,
mainnet_gas_price: withdraw_log.home_gas_price,
})
}
*/
pub fn from_home_deposit_log(log: Log) -> Result<Self, Error> {
/// Creates a message from a `Deposit` event that was logged on Home.
pub fn from_deposit_log(log: Log) -> Result<Self, Error> {
let raw_log = RawLog { topics: log.topics, data: log.data.0 };
let parsed = Deposit::default().parse_log(raw_log)?;
let tx_hash = parsed.transaction_hash
.ok_or_else(|| "`log` must be mined and contain `transaction_hash`")?;
let tx_hash = log.transaction_hash
.expect("Deposit event does not contain a `transaction_hash`");
let msg = MessageToMainnet {
recipient: parsed.recipient,
value: parsed.value,
@ -73,8 +53,7 @@ impl MessageToMainnet {
let mut result = vec![0u8; MESSAGE_LENGTH];
result[0..20].copy_from_slice(&self.recipient.0[..]);
result[20..52].copy_from_slice(&H256::from(self.value));
result[52..84].copy_from_slice(&self.sidenet_transaction_hash.0[..]);
// result[84..MESSAGE_LENGTH].copy_from_slice(&H256::from(self.mainnet_gas_price));
result[52..].copy_from_slice(&self.sidenet_transaction_hash.0[..]);
return result;
}
@ -93,8 +72,7 @@ mod test {
fn quickcheck_message_to_mainnet_roundtrips_to_bytes(
recipient_raw: Vec<u8>,
value_raw: u64,
sidenet_transaction_hash_raw: Vec<u8>,
// mainnet_gas_price_raw: u64
sidenet_transaction_hash_raw: Vec<u8>
) -> TestResult {
if recipient_raw.len() != 20 || sidenet_transaction_hash_raw.len() != 32 {
return TestResult::discard();
@ -103,13 +81,11 @@ mod test {
let recipient: Address = recipient_raw.as_slice().into();
let value: U256 = value_raw.into();
let sidenet_transaction_hash: H256 = sidenet_transaction_hash_raw.as_slice().into();
// let mainnet_gas_price: U256 = mainnet_gas_price_raw.into();
let message = MessageToMainnet {
recipient,
value,
sidenet_transaction_hash,
// mainnet_gas_price
};
let bytes = message.to_bytes();

View File

@ -13,7 +13,7 @@ extern crate jsonrpc_core as rpc;
#[macro_use]
extern crate version;
use std::{env, fs, io};
use std::{env, io};
use std::sync::Arc;
use std::path::PathBuf;
use docopt::Docopt;
@ -21,8 +21,9 @@ use futures::{Stream, future};
use tokio_core::reactor::Core;
use bridge::app::App;
use bridge::bridge::{create_bridge, create_deploy, create_chain_id_retrieval, Deployed};
use bridge::bridge::{create_bridge, create_chain_id_retrieval};
use bridge::config::Config;
use bridge::database::Database;
use bridge::error::{Error, ErrorKind};
use bridge::web3;
@ -69,18 +70,18 @@ impl From<(i32, Error)> for UserFacingError {
const USAGE: &'static str = r#"
POA-Ethereum bridge.
Copyright 2017 Parity Technologies (UK) Limited
Copyright 2018 POA Networks Ltd.
Copyright 2017 Parity Technologies (UK) Limited
Copyright 2018 POA Networks Ltd.
Usage:
bridge [options] --config <config> --database <database>
bridge -h | --help
bridge -v | --version
bridge [options] --config <config> --database <database>
bridge -h | --help
bridge -v | --version
Options:
-h, --help Display help message and exit.
-v, --version Print version and exit.
--allow-insecure-rpc-endpoints Allow non-HTTPS endpoints
-h, --help Display help message and exit.
-v, --version Print version and exit.
--allow-insecure-rpc-endpoints Allow non-HTTPS endpoints
"#;
#[derive(Debug, Deserialize)]
@ -95,7 +96,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
fn main() {
let _ = env_logger::init();
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
@ -167,25 +168,7 @@ fn execute<S, I>(command: I, running: Arc<AtomicBool>) -> Result<String, UserFac
*foreign_nonce = event_loop.run(api::eth_get_transaction_count(app.connections.foreign.clone(), app.config.foreign.account, None)).expect("can't initialize foreign nonce");
}
#[cfg(feature = "deploy")]
info!(target: "bridge", "Deploying contracts (if needed)");
#[cfg(not(feature = "deploy"))]
info!(target: "bridge", "Reading the database");
let deployed = event_loop.run(create_deploy(app.clone(), home_chain_id, foreign_chain_id))?;
let database = match deployed {
Deployed::New(database) => {
info!(target: "bridge", "Deployed new bridge contracts");
info!(target: "bridge", "\n\n{}\n", database);
database.save(fs::File::create(&app.database_path)?)?;
database
},
Deployed::Existing(database) => {
info!(target: "bridge", "Loaded database");
database
},
};
let database = Database::load(&app.database_path)?;
info!(target: "bridge", "Starting listening to events");
let bridge = create_bridge(app.clone(), &database, &handle, home_chain_id, foreign_chain_id).and_then(|_| future::ok(true)).collect();

View File

@ -136,11 +136,12 @@ macro_rules! test_app_stream {
use self::std::time::Duration;
use self::futures::{Future, Stream};
use self::bridge::app::{App, Connections};
use self::bridge::bridge::BridgeChecked;
use self::bridge::contracts::{foreign, home};
use self::bridge::config::{Config, Authorities, Node, NodeInfo, ContractConfig, Transactions, TransactionConfig, GasPriceSpeed};
use self::bridge::database::Database;
use ethcore::account_provider::AccountProvider;
let home = $crate::MockedTransport {
requests: Default::default(),
expected_requests: vec![$($home_method),*].into_iter().zip(vec![$($home_req),*].into_iter()).map(Into::into).collect(),
@ -171,6 +172,7 @@ macro_rules! test_app_stream {
gas_price_speed: GasPriceSpeed::Fast,
gas_price_timeout: Duration::from_secs(5),
default_gas_price: 0,
concurrent_http_requests: 64,
},
foreign: Node {
account: $foreign_acc.parse().unwrap(),
@ -188,6 +190,7 @@ macro_rules! test_app_stream {
gas_price_speed: GasPriceSpeed::Fast,
gas_price_timeout: Duration::from_secs(5),
default_gas_price: 0,
concurrent_http_requests: 64,
},
authorities: Authorities {
accounts: $authorities_accs.iter().map(|a: &&str| a.parse().unwrap()).collect(),
@ -213,9 +216,16 @@ macro_rules! test_app_stream {
let app = Arc::new(app);
let stream = $init_stream(app, &$db);
let res = stream.collect().wait();
assert_eq!($expected, res.unwrap());
let res: Vec<u64> = stream.collect().wait().unwrap().iter()
.map(|checked| match *checked {
BridgeChecked::DepositConfirm(block) => block,
BridgeChecked::DepositRelay(block) => block,
BridgeChecked::WithdrawRelay(block) => block,
})
.collect();
assert_eq!($expected, res);
assert_eq!(
home.expected_requests.len(),

View File

@ -146,8 +146,6 @@ test_app_stream! {
txs => Transactions {
deposit_relay: TransactionConfig {
gas: 0xfd,
gas_price: 0xa0,
concurrency: 100,
},
..Default::default()
},

View File

@ -1,3 +1,4 @@
/*
/// test interactions of withdraw_confirm state machine with RPC
extern crate futures;
@ -429,3 +430,4 @@ test_app_stream! {
res => json!([]);
]
}
*/

View File

@ -11,7 +11,7 @@ extern crate ethereum_types;
extern crate rustc_hex;
extern crate ethcore;
use ethereum_types::{U256, H256};
use ethereum_types::{H160, U256, H256};
use rustc_hex::ToHex;
use bridge::bridge::create_withdraw_relay;
@ -151,16 +151,12 @@ test_app_stream! {
.functions()
.withdraw()
.input(
vec![U256::from(1), U256::from(4)],
vec![H256::from(2), H256::from(5)],
vec![H256::from(3), H256::from(6)],
MessageToMainnet {
recipient: [1u8; 20].into(),
value: 10000.into(),
sidenet_transaction_hash: "0x884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into(),
mainnet_gas_price: 1000.into(),
}.to_bytes()
).to_hex()),
H160::from([1u8; 20]),
U256::from(10000),
H256::from("884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364")
)
.to_hex()
),
"from": "0x0000000000000000000000000000000000000001",
"gas": "0x0",
"gasPrice": "0x3e8",
@ -197,7 +193,6 @@ test_app_stream! {
recipient: [1u8; 20].into(),
value: 10000.into(),
sidenet_transaction_hash: "0x884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364".into(),
mainnet_gas_price: 1000.into(),
}.to_payload().to_hex()));
// calls to `signature`
"eth_call" =>