Fixed build errors in tests.
This commit is contained in:
parent
8fd93a679c
commit
9415b7356c
|
@ -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() {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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> {
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -146,8 +146,6 @@ test_app_stream! {
|
|||
txs => Transactions {
|
||||
deposit_relay: TransactionConfig {
|
||||
gas: 0xfd,
|
||||
gas_price: 0xa0,
|
||||
concurrency: 100,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -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!([]);
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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" =>
|
||||
|
|
Loading…
Reference in New Issue