From 6aa9005785a1c112247f626b5228d942ae26ee32 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 3 Apr 2017 11:37:07 +0200 Subject: [PATCH 01/29] parity_getBlockHeaderByNumber and LightFetch --- ethcore/light/src/client/mod.rs | 15 +++ rpc/src/v1/helpers/errors.rs | 5 + rpc/src/v1/helpers/light_fetch.rs | 200 ++++++++++++++++++++++++++++++ rpc/src/v1/helpers/mod.rs | 1 + rpc/src/v1/impls/eth.rs | 4 +- rpc/src/v1/impls/light/eth.rs | 179 ++++---------------------- rpc/src/v1/impls/light/parity.rs | 47 ++++++- rpc/src/v1/impls/parity.rs | 37 +++++- rpc/src/v1/traits/parity.rs | 7 +- rpc/src/v1/types/block.rs | 121 +++++++++++++++--- rpc/src/v1/types/mod.rs | 2 +- 11 files changed, 439 insertions(+), 179 deletions(-) create mode 100644 rpc/src/v1/helpers/light_fetch.rs diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index c791caed1..f340b5bcf 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -68,6 +68,13 @@ pub trait LightChainClient: Send + Sync { /// Get the signing network ID. fn signing_network_id(&self) -> Option; + /// Get environment info for execution at a given block. + /// Fails if that block's header is not stored. + fn env_info(&self, id: BlockId) -> Option; + + /// Get a handle to the consensus engine. + fn engine(&self) -> &Arc; + /// Query whether a block is known. fn is_known(&self, hash: &H256) -> bool; @@ -295,6 +302,14 @@ impl LightChainClient for Client { Client::signing_network_id(self) } + fn env_info(&self, id: BlockId) -> Option { + Client::env_info(self, id) + } + + fn engine(&self) -> &Arc { + Client::engine(self) + } + fn is_known(&self, hash: &H256) -> bool { self.status(hash) == BlockStatus::InChain } diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 7a7e940b8..aae6a97f3 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -346,3 +346,8 @@ pub fn deprecated>>(message: T) -> Error { data: message.into().map(Value::String), } } + +// on-demand sender cancelled. +pub fn on_demand_cancel(_cancel: ::futures::sync::oneshot::Canceled) -> Error { + internal("on-demand sender cancelled", "") +} diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs new file mode 100644 index 000000000..e2ce6880f --- /dev/null +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -0,0 +1,200 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Helpers for fetching blockchain data either from the light client or the network. + +use std::sync::Arc; + +use ethcore::basic_account::BasicAccount; +use ethcore::encoded; +use ethcore::executed::{Executed, ExecutionError}; +use ethcore::ids::BlockId; +use ethcore::transaction::{Action, Transaction as EthTransaction}; + +use futures::{future, Future, BoxFuture}; +use jsonrpc_core::Error; +use jsonrpc_macros::Trailing; + +use light::cache::Cache; +use light::client::LightChainClient; +use light::cht; +use light::on_demand::{OnDemand, request}; + +use ethsync::LightSync; +use util::{Address, Mutex, Uint, U256}; + +use v1::helpers::{CallRequest as CRequest, errors, dispatch}; +use v1::types::{BlockNumber, CallRequest}; + +/// Helper for fetching blockchain data either from the light client or the network +/// as necessary. +pub struct LightFetch { + /// The light client. + pub client: Arc, + /// The on-demand request service. + pub on_demand: Arc, + /// Handle to the network. + pub sync: Arc, + /// The light data cache. + pub cache: Arc>, +} + +/// Type alias for convenience. +pub type ExecutionResult = Result; + +impl LightFetch { + /// Get a block header from the on demand service or client, or error. + pub fn header(&self, id: BlockId) -> BoxFuture, Error> { + if let Some(h) = self.client.block_header(id) { + return future::ok(Some(h)).boxed() + } + + let maybe_future = match id { + BlockId::Number(n) => { + let cht_root = cht::block_to_cht_number(n).and_then(|cn| self.client.cht_root(cn as usize)); + match cht_root { + None => return future::ok(None).boxed(), + Some(root) => { + let req = request::HeaderProof::new(n, root) + .expect("only fails for 0; client always stores genesis; client already queried; qed"); + + let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); + self.sync.with_context(|ctx| { + let fut = self.on_demand.hash_by_number(ctx, req) + .map(request::HeaderByHash) + .map_err(errors::on_demand_cancel); + + fut.and_then(move |req| { + match sync.with_context(|ctx| on_demand.header_by_hash(ctx, req)) { + Some(fut) => fut.map_err(errors::on_demand_cancel).boxed(), + None => future::err(errors::network_disabled()).boxed(), + } + }).map(Some).boxed() + }) + } + } + } + BlockId::Hash(h) => { + self.sync.with_context(|ctx| + self.on_demand.header_by_hash(ctx, request::HeaderByHash(h)) + .then(|res| future::done(match res { + Ok(h) => Ok(Some(h)), + Err(e) => Err(errors::on_demand_cancel(e)), + })) + .boxed() + ) + } + _ => None, // latest, earliest, and pending will have all already returned. + }; + + match maybe_future { + Some(recv) => recv, + None => future::err(errors::network_disabled()).boxed() + } + } + + // Get account info at a given block. `None` signifies no such account existing. + pub fn account(&self, address: Address, id: BlockId) -> BoxFuture, Error> { + let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); + + self.header(id).and_then(move |header| { + let header = match header { + None => return future::ok(None).boxed(), + Some(hdr) => hdr, + }; + + sync.with_context(|ctx| on_demand.account(ctx, request::Account { + header: header, + address: address, + })) + .map(|x| x.map_err(errors::on_demand_cancel).boxed()) + .unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) + }).boxed() + } + + /// helper for getting proved execution. + pub fn proved_execution(&self, req: CallRequest, num: Trailing) -> BoxFuture { + const DEFAULT_GAS_PRICE: U256 = U256([0, 0, 0, 21_000_000]); + + let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone()); + let req: CRequest = req.into(); + let id = num.0.into(); + + let from = req.from.unwrap_or(Address::zero()); + let nonce_fut = match req.nonce { + Some(nonce) => future::ok(Some(nonce)).boxed(), + None => self.account(from, id).map(|acc| acc.map(|a| a.nonce)).boxed(), + }; + + let gas_price_fut = match req.gas_price { + Some(price) => future::ok(price).boxed(), + None => dispatch::fetch_gas_price_corpus( + self.sync.clone(), + self.client.clone(), + self.on_demand.clone(), + self.cache.clone(), + ).map(|corp| match corp.median() { + Some(median) => *median, + None => DEFAULT_GAS_PRICE, + }).boxed() + }; + + // if nonce resolves, this should too since it'll be in the LRU-cache. + let header_fut = self.header(id); + + // fetch missing transaction fields from the network. + nonce_fut.join(gas_price_fut).and_then(move |(nonce, gas_price)| { + let action = req.to.map_or(Action::Create, Action::Call); + let gas = req.gas.unwrap_or(U256::from(10_000_000)); // better gas amount? + let value = req.value.unwrap_or_else(U256::zero); + let data = req.data.map_or_else(Vec::new, |d| d.to_vec()); + + future::done(match nonce { + Some(n) => Ok(EthTransaction { + nonce: n, + action: action, + gas: gas, + gas_price: gas_price, + value: value, + data: data, + }.fake_sign(from)), + None => Err(errors::unknown_block()), + }) + }).join(header_fut).and_then(move |(tx, hdr)| { + // then request proved execution. + // TODO: get last-hashes from network. + let (env_info, hdr) = match (client.env_info(id), hdr) { + (Some(env_info), Some(hdr)) => (env_info, hdr), + _ => return future::err(errors::unknown_block()).boxed(), + }; + let request = request::TransactionProof { + tx: tx, + header: hdr, + env_info: env_info, + engine: client.engine().clone(), + }; + + let proved_future = sync.with_context(move |ctx| { + on_demand.transaction_proof(ctx, request).map_err(errors::on_demand_cancel).boxed() + }); + + match proved_future { + Some(fut) => fut.boxed(), + None => future::err(errors::network_disabled()).boxed(), + } + }).boxed() + } +} diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index 9d2064aa8..839d6b090 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -21,6 +21,7 @@ pub mod accounts; pub mod block_import; pub mod dispatch; pub mod fake_sign; +pub mod light_fetch; pub mod informant; pub mod oneshot; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 73d4d9f9b..d4265233a 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -146,7 +146,7 @@ impl EthClient where (Some(block), Some(total_difficulty)) => { let view = block.header_view(); Ok(Some(RichBlock { - block: Block { + inner: Block { hash: Some(view.sha3().into()), size: Some(block.rlp().as_raw().len().into()), parent_hash: view.parent_hash().into(), @@ -202,7 +202,7 @@ impl EthClient where .map(Into::into); let block = RichBlock { - block: Block { + inner: Block { hash: Some(uncle.hash().into()), size: size, parent_hash: uncle.parent_hash().clone().into(), diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 251daf90d..6f283af02 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -45,6 +45,7 @@ use futures::sync::oneshot; use v1::helpers::{CallRequest as CRequest, errors, limit_logs, dispatch}; use v1::helpers::block_import::is_major_importing; +use v1::helpers::light_fetch::LightFetch; use v1::traits::Eth; use v1::types::{ RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, @@ -65,12 +66,6 @@ pub struct EthClient { cache: Arc>, } -// helper for internal error: on demand sender cancelled. -fn err_premature_cancel(_cancel: oneshot::Canceled) -> Error { - errors::internal("on-demand sender prematurely cancelled", "") -} - -type ExecutionResult = Result; impl EthClient { /// Create a new `EthClient` with a handle to the light sync instance, client, @@ -93,147 +88,15 @@ impl EthClient { } } - /// Get a block header from the on demand service or client, or error. - fn header(&self, id: BlockId) -> BoxFuture, Error> { - if let Some(h) = self.client.block_header(id) { - return future::ok(Some(h)).boxed() + /// Create a light data fetcher instance. + fn fetcher(&self) -> LightFetch { + LightFetch { + client: self.client.clone(), + on_demand: self.on_demand.clone(), + sync: self.sync.clone(), + cache: self.cache.clone(), + } - - let maybe_future = match id { - BlockId::Number(n) => { - let cht_root = cht::block_to_cht_number(n).and_then(|cn| self.client.cht_root(cn as usize)); - match cht_root { - None => return future::ok(None).boxed(), - Some(root) => { - let req = request::HeaderProof::new(n, root) - .expect("only fails for 0; client always stores genesis; client already queried; qed"); - - let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - self.sync.with_context(|ctx| { - let fut = self.on_demand.hash_by_number(ctx, req) - .map(request::HeaderByHash) - .map_err(err_premature_cancel); - - fut.and_then(move |req| { - match sync.with_context(|ctx| on_demand.header_by_hash(ctx, req)) { - Some(fut) => fut.map_err(err_premature_cancel).boxed(), - None => future::err(errors::network_disabled()).boxed(), - } - }).map(Some).boxed() - }) - } - } - } - BlockId::Hash(h) => { - self.sync.with_context(|ctx| - self.on_demand.header_by_hash(ctx, request::HeaderByHash(h)) - .then(|res| future::done(match res { - Ok(h) => Ok(Some(h)), - Err(e) => Err(err_premature_cancel(e)), - })) - .boxed() - ) - } - _ => None, // latest, earliest, and pending will have all already returned. - }; - - match maybe_future { - Some(recv) => recv, - None => future::err(errors::network_disabled()).boxed() - } - } - - // helper for getting account info at a given block. - fn account(&self, address: Address, id: BlockId) -> BoxFuture, Error> { - let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - - self.header(id).and_then(move |header| { - let header = match header { - None => return future::ok(None).boxed(), - Some(hdr) => hdr, - }; - - sync.with_context(|ctx| on_demand.account(ctx, request::Account { - header: header, - address: address, - })) - .map(|x| x.map_err(err_premature_cancel).boxed()) - .unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) - }).boxed() - } - - // helper for getting proved execution. - fn proved_execution(&self, req: CallRequest, num: Trailing) -> BoxFuture { - const DEFAULT_GAS_PRICE: U256 = U256([0, 0, 0, 21_000_000]); - - - let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone()); - let req: CRequest = req.into(); - let id = num.0.into(); - - let from = req.from.unwrap_or(Address::zero()); - let nonce_fut = match req.nonce { - Some(nonce) => future::ok(Some(nonce)).boxed(), - None => self.account(from, id).map(|acc| acc.map(|a| a.nonce)).boxed(), - }; - - let gas_price_fut = match req.gas_price { - Some(price) => future::ok(price).boxed(), - None => dispatch::fetch_gas_price_corpus( - self.sync.clone(), - self.client.clone(), - self.on_demand.clone(), - self.cache.clone(), - ).map(|corp| match corp.median() { - Some(median) => *median, - None => DEFAULT_GAS_PRICE, - }).boxed() - }; - - // if nonce resolves, this should too since it'll be in the LRU-cache. - let header_fut = self.header(id); - - // fetch missing transaction fields from the network. - nonce_fut.join(gas_price_fut).and_then(move |(nonce, gas_price)| { - let action = req.to.map_or(Action::Create, Action::Call); - let gas = req.gas.unwrap_or(U256::from(10_000_000)); // better gas amount? - let value = req.value.unwrap_or_else(U256::zero); - let data = req.data.map_or_else(Vec::new, |d| d.to_vec()); - - future::done(match nonce { - Some(n) => Ok(EthTransaction { - nonce: n, - action: action, - gas: gas, - gas_price: gas_price, - value: value, - data: data, - }.fake_sign(from)), - None => Err(errors::unknown_block()), - }) - }).join(header_fut).and_then(move |(tx, hdr)| { - // then request proved execution. - // TODO: get last-hashes from network. - let (env_info, hdr) = match (client.env_info(id), hdr) { - (Some(env_info), Some(hdr)) => (env_info, hdr), - _ => return future::err(errors::unknown_block()).boxed(), - }; - let request = request::TransactionProof { - tx: tx, - header: hdr, - env_info: env_info, - engine: client.engine().clone(), - }; - - let proved_future = sync.with_context(move |ctx| { - on_demand.transaction_proof(ctx, request).map_err(err_premature_cancel).boxed() - }); - - match proved_future { - Some(fut) => fut.boxed(), - None => future::err(errors::network_disabled()).boxed(), - } - }).boxed() } } @@ -281,7 +144,7 @@ impl Eth for EthClient { } fn balance(&self, address: RpcH160, num: Trailing) -> BoxFuture { - self.account(address.into(), num.0.into()) + self.fetcher().account(address.into(), num.0.into()) .map(|acc| acc.map_or(0.into(), |a| a.balance).into()).boxed() } @@ -298,14 +161,14 @@ impl Eth for EthClient { } fn transaction_count(&self, address: RpcH160, num: Trailing) -> BoxFuture { - self.account(address.into(), num.0.into()) + self.fetcher().account(address.into(), num.0.into()) .map(|acc| acc.map_or(0.into(), |a| a.nonce).into()).boxed() } fn block_transaction_count_by_hash(&self, hash: RpcH256) -> BoxFuture, Error> { let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - self.header(BlockId::Hash(hash.into())).and_then(move |hdr| { + self.fetcher().header(BlockId::Hash(hash.into())).and_then(move |hdr| { let hdr = match hdr { None => return future::ok(None).boxed(), Some(hdr) => hdr, @@ -316,7 +179,7 @@ impl Eth for EthClient { } else { sync.with_context(|ctx| on_demand.block(ctx, request::Body::new(hdr))) .map(|x| x.map(|b| Some(U256::from(b.transactions_count()).into()))) - .map(|x| x.map_err(err_premature_cancel).boxed()) + .map(|x| x.map_err(errors::on_demand_cancel).boxed()) .unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) } }).boxed() @@ -325,7 +188,7 @@ impl Eth for EthClient { fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture, Error> { let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - self.header(num.into()).and_then(move |hdr| { + self.fetcher().header(num.into()).and_then(move |hdr| { let hdr = match hdr { None => return future::ok(None).boxed(), Some(hdr) => hdr, @@ -336,7 +199,7 @@ impl Eth for EthClient { } else { sync.with_context(|ctx| on_demand.block(ctx, request::Body::new(hdr))) .map(|x| x.map(|b| Some(U256::from(b.transactions_count()).into()))) - .map(|x| x.map_err(err_premature_cancel).boxed()) + .map(|x| x.map_err(errors::on_demand_cancel).boxed()) .unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) } }).boxed() @@ -345,7 +208,7 @@ impl Eth for EthClient { fn block_uncles_count_by_hash(&self, hash: RpcH256) -> BoxFuture, Error> { let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - self.header(BlockId::Hash(hash.into())).and_then(move |hdr| { + self.fetcher().header(BlockId::Hash(hash.into())).and_then(move |hdr| { let hdr = match hdr { None => return future::ok(None).boxed(), Some(hdr) => hdr, @@ -356,7 +219,7 @@ impl Eth for EthClient { } else { sync.with_context(|ctx| on_demand.block(ctx, request::Body::new(hdr))) .map(|x| x.map(|b| Some(U256::from(b.uncles_count()).into()))) - .map(|x| x.map_err(err_premature_cancel).boxed()) + .map(|x| x.map_err(errors::on_demand_cancel).boxed()) .unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) } }).boxed() @@ -365,7 +228,7 @@ impl Eth for EthClient { fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture, Error> { let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - self.header(num.into()).and_then(move |hdr| { + self.fetcher().header(num.into()).and_then(move |hdr| { let hdr = match hdr { None => return future::ok(None).boxed(), Some(hdr) => hdr, @@ -376,7 +239,7 @@ impl Eth for EthClient { } else { sync.with_context(|ctx| on_demand.block(ctx, request::Body::new(hdr))) .map(|x| x.map(|b| Some(U256::from(b.uncles_count()).into()))) - .map(|x| x.map_err(err_premature_cancel).boxed()) + .map(|x| x.map_err(errors::on_demand_cancel).boxed()) .unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) } }).boxed() @@ -411,7 +274,7 @@ impl Eth for EthClient { } fn call(&self, req: CallRequest, num: Trailing) -> BoxFuture { - self.proved_execution(req, num).and_then(|res| { + self.fetcher().proved_execution(req, num).and_then(|res| { match res { Ok(exec) => Ok(exec.output.into()), Err(e) => Err(errors::execution(e)), @@ -421,7 +284,7 @@ impl Eth for EthClient { fn estimate_gas(&self, req: CallRequest, num: Trailing) -> BoxFuture { // TODO: binary chop for more accurate estimates. - self.proved_execution(req, num).and_then(|res| { + self.fetcher().proved_execution(req, num).and_then(|res| { match res { Ok(exec) => Ok((exec.refunded + exec.gas_used).into()), Err(e) => Err(errors::execution(e)), diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 569398193..65cc90966 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -32,6 +32,7 @@ use jsonrpc_core::Error; use jsonrpc_macros::Trailing; use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::dispatch::{LightDispatcher, DEFAULT_MAC}; +use v1::helpers::light_fetch::LightFetch; use v1::metadata::Metadata; use v1::traits::Parity; use v1::types::{ @@ -40,7 +41,7 @@ use v1::types::{ TransactionStats, LocalTransactionStatus, BlockNumber, ConsensusCapability, VersionInfo, OperationsInfo, DappId, ChainStatus, - AccountInfo, HwAccountInfo, + AccountInfo, HwAccountInfo, Header, RichHeader, }; /// Parity implementation for light client. @@ -75,6 +76,16 @@ impl ParityClient { dapps_port: dapps_port, } } + + /// Create a light blockchain data fetcher. + fn fetcher(&self) -> LightFetch { + LightFetch { + client: self.light_dispatch.client.clone(), + on_demand: self.light_dispatch.on_demand.clone(), + sync: self.light_dispatch.sync.clone(), + cache: self.light_dispatch.cache.clone(), + } + } } impl Parity for ParityClient { @@ -342,4 +353,38 @@ impl Parity for ParityClient { capability: Capability::Light, }) } + + fn block_header(&self, number: Trailing) -> BoxFuture, Error> { + use ethcore::encoded; + + let engine = self.light_dispatch.client.engine().clone(); + let from_encoded = move |encoded: encoded::Header| { + let header = encoded.decode(); + let extra_info = engine.extra_info(&header); + RichHeader { + inner: Header { + hash: Some(header.hash().into()), + size: Some(encoded.rlp().as_raw().len().into()), + parent_hash: header.parent_hash().clone().into(), + uncles_hash: header.uncles_hash().clone().into(), + author: header.author().clone().into(), + miner: header.author().clone().into(), + state_root: header.state_root().clone().into(), + transactions_root: header.transactions_root().clone().into(), + receipts_root: header.receipts_root().clone().into(), + number: Some(header.number().into()), + gas_used: header.gas_used().clone().into(), + gas_limit: header.gas_limit().clone().into(), + logs_bloom: header.log_bloom().clone().into(), + timestamp: header.timestamp().into(), + difficulty: header.difficulty().clone().into(), + seal_fields: header.seal().iter().cloned().map(Into::into).collect(), + extra_data: Bytes::new(header.extra_data().clone()), + }, + extra_info: extra_info, + } + }; + + self.fetcher().header(number.0.into()).map(move |encoded| encoded.map(from_encoded)).boxed() + } } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 83e0a505d..d2934313e 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -28,6 +28,7 @@ use crypto::ecies; use ethkey::{Brain, Generator}; use ethstore::random_phrase; use ethsync::{SyncProvider, ManageNetwork}; +use ethcore::ids::BlockId; use ethcore::miner::MinerService; use ethcore::client::{MiningBlockChainClient}; use ethcore::mode::Mode; @@ -47,7 +48,7 @@ use v1::types::{ TransactionStats, LocalTransactionStatus, BlockNumber, ConsensusCapability, VersionInfo, OperationsInfo, DappId, ChainStatus, - AccountInfo, HwAccountInfo, + AccountInfo, HwAccountInfo, Header, RichHeader }; /// Parity implementation. @@ -393,4 +394,38 @@ impl Parity for ParityClient where capability: Capability::Full, }) } + + fn block_header(&self, number: Trailing) -> BoxFuture, Error> { + const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; + + let client = take_weakf!(self.client); + let id: BlockId = number.0.into(); + let encoded = match client.block_header(id.clone()) { + Some(encoded) => encoded, + None => return future::ok(None).boxed(), + }; + + future::ok(Some(RichHeader { + inner: Header { + hash: Some(encoded.hash().into()), + size: Some(encoded.rlp().as_raw().len().into()), + parent_hash: encoded.parent_hash().into(), + uncles_hash: encoded.uncles_hash().into(), + author: encoded.author().into(), + miner: encoded.author().into(), + state_root: encoded.state_root().into(), + transactions_root: encoded.transactions_root().into(), + receipts_root: encoded.receipts_root().into(), + number: Some(encoded.number().into()), + gas_used: encoded.gas_used().into(), + gas_limit: encoded.gas_limit().into(), + logs_bloom: encoded.log_bloom().into(), + timestamp: encoded.timestamp().into(), + difficulty: encoded.difficulty().into(), + seal_fields: encoded.seal().into_iter().map(Into::into).collect(), + extra_data: Bytes::new(encoded.extra_data()), + }, + extra_info: client.block_extra_info(id).expect(EXTRA_INFO_PROOF), + })).boxed() + } } diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 8a15addae..b374ebd53 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -28,7 +28,7 @@ use v1::types::{ TransactionStats, LocalTransactionStatus, BlockNumber, ConsensusCapability, VersionInfo, OperationsInfo, DappId, ChainStatus, - AccountInfo, HwAccountInfo, + AccountInfo, HwAccountInfo, RichHeader, }; build_rpc_trait! { @@ -198,5 +198,10 @@ build_rpc_trait! { /// Get node kind info. #[rpc(name = "parity_nodeKind")] fn node_kind(&self) -> Result<::v1::types::NodeKind, Error>; + + /// Get block header. + /// Same as `eth_getBlockByNumber` but without uncles and transactions. + #[rpc(async, name = "parity_getBlockHeaderByNumber")] + fn block_header(&self, Trailing) -> BoxFuture, Error>; } } diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index e63137520..4077d7221 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -96,34 +96,90 @@ pub struct Block { pub size: Option, } -/// Block representation with additional info +/// Block header representation. +#[derive(Debug, Serialize)] +pub struct Header { + /// Hash of the block + pub hash: Option, + /// Hash of the parent + #[serde(rename="parentHash")] + pub parent_hash: H256, + /// Hash of the uncles + #[serde(rename="sha3Uncles")] + pub uncles_hash: H256, + /// Authors address + pub author: H160, + // TODO: get rid of this one + /// ? + pub miner: H160, + /// State root hash + #[serde(rename="stateRoot")] + pub state_root: H256, + /// Transactions root hash + #[serde(rename="transactionsRoot")] + pub transactions_root: H256, + /// Transactions receipts root hash + #[serde(rename="receiptsRoot")] + pub receipts_root: H256, + /// Block number + pub number: Option, + /// Gas Used + #[serde(rename="gasUsed")] + pub gas_used: U256, + /// Gas Limit + #[serde(rename="gasLimit")] + pub gas_limit: U256, + /// Extra data + #[serde(rename="extraData")] + pub extra_data: Bytes, + /// Logs bloom + #[serde(rename="logsBloom")] + pub logs_bloom: H2048, + /// Timestamp + pub timestamp: U256, + /// Difficulty + pub difficulty: U256, + /// Seal fields + #[serde(rename="sealFields")] + pub seal_fields: Vec, + /// Size in bytes + pub size: Option, +} + +/// Block representation with additional info. +pub type RichBlock = Rich; + +/// Header representation with additional info. +pub type RichHeader = Rich
; + +/// Value representation with additional info #[derive(Debug)] -pub struct RichBlock { - /// Standard block - pub block: Block, +pub struct Rich { + /// Standard value. + pub inner: T, /// Engine-specific fields with additional description. /// Should be included directly to serialized block object. // TODO [ToDr] #[serde(skip_serializing)] pub extra_info: BTreeMap, } -impl Deref for RichBlock { - type Target = Block; +impl Deref for Rich { + type Target = T; fn deref(&self) -> &Self::Target { - &self.block + &self.inner } } -impl Serialize for RichBlock { +impl Serialize for Rich { fn serialize(&self, serializer: S) -> Result where S: Serializer { use serde_json::{to_value, Value}; - let serialized = (to_value(&self.block), to_value(&self.extra_info)); - if let (Ok(Value::Object(mut block)), Ok(Value::Object(extras))) = serialized { + let serialized = (to_value(&self.inner), to_value(&self.extra_info)); + if let (Ok(Value::Object(mut value)), Ok(Value::Object(extras))) = serialized { // join two objects - block.extend(extras); + value.extend(extras); // and serialize - block.serialize(serializer) + value.serialize(serializer) } else { Err(S::Error::custom("Unserializable structures.")) } @@ -135,7 +191,7 @@ mod tests { use std::collections::BTreeMap; use serde_json; use v1::types::{Transaction, H64, H160, H256, H2048, Bytes, U256}; - use super::{Block, RichBlock, BlockTransactions}; + use super::{Block, RichBlock, BlockTransactions, Header, RichHeader}; #[test] fn test_serialize_block_transactions() { @@ -174,7 +230,7 @@ mod tests { }; let serialized_block = serde_json::to_string(&block).unwrap(); let rich_block = RichBlock { - block: block, + inner: block, extra_info: map![ "mixHash".into() => format!("0x{:?}", H256::default()), "nonce".into() => format!("0x{:?}", H64::default()) @@ -212,7 +268,7 @@ mod tests { }; let serialized_block = serde_json::to_string(&block).unwrap(); let rich_block = RichBlock { - block: block, + inner: block, extra_info: map![ "mixHash".into() => format!("0x{:?}", H256::default()), "nonce".into() => format!("0x{:?}", H64::default()) @@ -223,4 +279,39 @@ mod tests { assert_eq!(serialized_block, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x0","gasUsed":"0x0","gasLimit":"0x0","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","difficulty":"0x0","totalDifficulty":"0x0","sealFields":["0x","0x"],"uncles":[],"transactions":[],"size":null}"#); assert_eq!(serialized_rich_block, r#"{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","sealFields":["0x","0x"],"sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","size":null,"stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","totalDifficulty":"0x0","transactions":[],"transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","uncles":[]}"#); } + + #[test] + fn test_serialize_header() { + let header = Header { + hash: Some(H256::default()), + parent_hash: H256::default(), + uncles_hash: H256::default(), + author: H160::default(), + miner: H160::default(), + state_root: H256::default(), + transactions_root: H256::default(), + receipts_root: H256::default(), + number: Some(U256::default()), + gas_used: U256::default(), + gas_limit: U256::default(), + extra_data: Bytes::default(), + logs_bloom: H2048::default(), + timestamp: U256::default(), + difficulty: U256::default(), + seal_fields: vec![Bytes::default(), Bytes::default()], + size: Some(69.into()), + }; + let serialized_header = serde_json::to_string(&header).unwrap(); + let rich_header = RichHeader { + inner: header, + extra_info: map![ + "mixHash".into() => format!("0x{:?}", H256::default()), + "nonce".into() => format!("0x{:?}", H64::default()) + ], + }; + let serialized_rich_header = serde_json::to_string(&rich_header).unwrap(); + + assert_eq!(serialized_header, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x0","gasUsed":"0x0","gasLimit":"0x0","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","difficulty":"0x0","sealFields":["0x","0x"],"size":"0x45"}"#); + assert_eq!(serialized_rich_header, r#"{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","sealFields":["0x","0x"],"sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","size":"0x45","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#); + } } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 0ec60a74f..d76c92deb 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -45,7 +45,7 @@ mod work; pub use self::account_info::{AccountInfo, HwAccountInfo}; pub use self::bytes::Bytes; -pub use self::block::{RichBlock, Block, BlockTransactions}; +pub use self::block::{RichBlock, Block, BlockTransactions, Header, RichHeader, Rich}; pub use self::block_number::BlockNumber; pub use self::call_request::CallRequest; pub use self::confirmations::{ From 564a1b0fbb48b20b6be0d2488d43fca35e6cc28b Mon Sep 17 00:00:00 2001 From: maciejhirsz Date: Thu, 6 Apr 2017 17:13:53 +0200 Subject: [PATCH 02/29] Tests and tweaks for public node middleware --- js/src/api/api.js | 2 +- js/src/api/local/ethkey/dummy.js | 19 --- js/src/api/local/ethkey/index.spec.js | 8 +- js/src/api/local/ethkey/worker.js | 22 ++- js/src/api/local/ethkey/workerPool.js | 9 +- js/src/api/local/index.js | 2 +- ...ddleware.js => localAccountsMiddleware.js} | 11 +- .../api/local/localAccountsMiddleware.spec.js | 154 ++++++++++++++++++ js/src/api/local/transactions.js | 18 +- js/src/api/local/transactions.spec.js | 17 ++ js/src/api/transport/jsonRpcBase.js | 14 +- js/src/api/transport/middleware.js | 4 +- js/src/api/transport/middleware.spec.js | 16 +- js/webpack/app.js | 4 +- js/webpack/libraries.js | 4 +- js/webpack/npm.js | 1 - 16 files changed, 241 insertions(+), 64 deletions(-) delete mode 100644 js/src/api/local/ethkey/dummy.js rename js/src/api/local/{middleware.js => localAccountsMiddleware.js} (94%) create mode 100644 js/src/api/local/localAccountsMiddleware.spec.js diff --git a/js/src/api/api.js b/js/src/api/api.js index 5be20371e..2c102086f 100644 --- a/js/src/api/api.js +++ b/js/src/api/api.js @@ -55,7 +55,7 @@ export default class Api extends EventEmitter { .nodeKind() .then((nodeKind) => { if (nodeKind.availability === 'public') { - return new LocalAccountsMiddleware(transport); + return LocalAccountsMiddleware; } return null; diff --git a/js/src/api/local/ethkey/dummy.js b/js/src/api/local/ethkey/dummy.js deleted file mode 100644 index 38f7c84de..000000000 --- a/js/src/api/local/ethkey/dummy.js +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -export default function () { - // empty file included while building parity.js (don't include local keygen) -} diff --git a/js/src/api/local/ethkey/index.spec.js b/js/src/api/local/ethkey/index.spec.js index c727e1d51..781c49b5c 100644 --- a/js/src/api/local/ethkey/index.spec.js +++ b/js/src/api/local/ethkey/index.spec.js @@ -18,8 +18,8 @@ import { randomPhrase } from '@parity/wordlist'; import { phraseToAddress, phraseToWallet } from './'; describe('api/local/ethkey', () => { - describe.skip('phraseToAddress', function () { - this.timeout(10000); + describe('phraseToAddress', function () { + this.timeout(30000); it('generates a valid address', () => { const phrase = randomPhrase(12); @@ -37,8 +37,8 @@ describe('api/local/ethkey', () => { }); }); - describe.skip('phraseToWallet', function () { - this.timeout(10000); + describe('phraseToWallet', function () { + this.timeout(30000); it('generates a valid wallet object', () => { const phrase = randomPhrase(12); diff --git a/js/src/api/local/ethkey/worker.js b/js/src/api/local/ethkey/worker.js index 00f4a0bed..ffb99d0e8 100644 --- a/js/src/api/local/ethkey/worker.js +++ b/js/src/api/local/ethkey/worker.js @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import secp256k1 from 'secp256k1/js'; +import secp256k1 from 'secp256k1'; import { keccak_256 as keccak256 } from 'js-sha3'; import { bytesToHex } from '~/api/util/format'; @@ -28,11 +28,9 @@ if (!isWorker) { } // keythereum should never be used outside of the browser -let keythereum = null; +let keythereum = require('keythereum'); if (isWorker) { - require('keythereum/dist/keythereum'); - keythereum = self.keythereum; } @@ -109,9 +107,13 @@ const actions = { }; self.onmessage = function ({ data }) { - const result = route(data); + try { + const result = route(data); - postMessage(result); + postMessage([null, result]); + } catch (err) { + postMessage([err, null]); + } }; // Emulate a web worker in Node.js @@ -119,9 +121,13 @@ class KeyWorker { postMessage (data) { // Force async setTimeout(() => { - const result = route(data); + try { + const result = route(data); - this.onmessage({ data: result }); + this.onmessage({ data: [null, result] }); + } catch (err) { + this.onmessage({ data: [err, null] }); + } }, 0); } diff --git a/js/src/api/local/ethkey/workerPool.js b/js/src/api/local/ethkey/workerPool.js index ff5315898..e4e4a5134 100644 --- a/js/src/api/local/ethkey/workerPool.js +++ b/js/src/api/local/ethkey/workerPool.js @@ -33,8 +33,15 @@ class WorkerContainer { return new Promise((resolve, reject) => { this._worker.postMessage({ action, payload }); this._worker.onmessage = ({ data }) => { + const [err, result] = data; + this.busy = false; - resolve(data); + + if (err) { + reject(err); + } else { + resolve(result); + } }; }); } diff --git a/js/src/api/local/index.js b/js/src/api/local/index.js index c1d4b60ca..1000fa330 100644 --- a/js/src/api/local/index.js +++ b/js/src/api/local/index.js @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -export LocalAccountsMiddleware from './middleware'; +export LocalAccountsMiddleware from './localAccountsMiddleware'; diff --git a/js/src/api/local/middleware.js b/js/src/api/local/localAccountsMiddleware.js similarity index 94% rename from js/src/api/local/middleware.js rename to js/src/api/local/localAccountsMiddleware.js index 36a8cd2cf..05eefb3ca 100644 --- a/js/src/api/local/middleware.js +++ b/js/src/api/local/localAccountsMiddleware.js @@ -23,15 +23,6 @@ import { phraseToWallet, phraseToAddress, verifySecret } from './ethkey'; import { randomPhrase } from '@parity/wordlist'; export default class LocalAccountsMiddleware extends Middleware { - // Maps transaction requests to transaction hashes. - // This allows the locally-signed transactions to emulate the signer. - transactionHashes = {}; - transactions = {}; - - // Current transaction id. This doesn't need to be stored, as it's - // only relevant for the current the session. - transactionId = 1; - constructor (transport) { super(transport); @@ -170,6 +161,8 @@ export default class LocalAccountsMiddleware extends Middleware { data } = Object.assign(transactions.get(id), modify); + transactions.lock(id); + const account = accounts.get(from); return Promise.all([ diff --git a/js/src/api/local/localAccountsMiddleware.spec.js b/js/src/api/local/localAccountsMiddleware.spec.js new file mode 100644 index 000000000..7408b4b1e --- /dev/null +++ b/js/src/api/local/localAccountsMiddleware.spec.js @@ -0,0 +1,154 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import LocalAccountsMiddleware from './localAccountsMiddleware'; +import JsonRpcBase from '../transport/jsonRpcBase'; + +const RPC_RESPONSE = Symbol('RPC response'); +const ADDRESS = '0x00a329c0648769a73afac7f9381e08fb43dbea72'; +const SECRET = '0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7'; +const PASSWORD = 'password'; + +const FOO_PHRASE = 'foobar'; +const FOO_PASSWORD = 'foopass'; +const FOO_ADDRESS = '0x007ef7ac1058e5955e366ab9d6b6c4ebcc937e7e'; + +class MockedTransport extends JsonRpcBase { + _execute (method, params) { + return RPC_RESPONSE; + } +} + +describe('api/local/LocalAccountsMiddleware', function () { + this.timeout(30000); + + let transport; + + beforeEach(() => { + transport = new MockedTransport(); + transport.addMiddleware(LocalAccountsMiddleware); + + // Same as `parity_newAccountFromPhrase` with empty phrase + return transport + .execute('parity_newAccountFromSecret', SECRET, PASSWORD) + .catch((_err) => { + // Ignore the error - all instances of LocalAccountsMiddleware + // share account storage + }); + }); + + it('registers all necessary methods', () => { + return Promise + .all([ + 'eth_accounts', + 'eth_coinbase', + 'parity_accountsInfo', + 'parity_allAccountsInfo', + 'parity_changePassword', + 'parity_checkRequest', + 'parity_defaultAccount', + 'parity_generateSecretPhrase', + 'parity_getNewDappsAddresses', + 'parity_hardwareAccountsInfo', + 'parity_newAccountFromPhrase', + 'parity_newAccountFromSecret', + 'parity_setAccountMeta', + 'parity_setAccountName', + 'parity_postTransaction', + 'parity_phraseToAddress', + 'parity_useLocalAccounts', + 'parity_listGethAccounts', + 'parity_listRecentDapps', + 'parity_killAccount', + 'parity_testPassword', + 'signer_confirmRequest', + 'signer_rejectRequest', + 'signer_requestsToConfirm' + ].map((method) => { + return transport + .execute(method) + .then((result) => { + expect(result).not.to.be.equal(RPC_RESPONSE); + }) + // Some errors are expected here since we are calling methods + // without parameters. + .catch((_) => {}); + })); + }); + + it('allows non-registered methods through', () => { + return transport + .execute('eth_getBalance', '0x407d73d8a49eeb85d32cf465507dd71d507100c1') + .then((result) => { + expect(result).to.be.equal(RPC_RESPONSE); + }); + }); + + it('can handle `eth_accounts`', () => { + return transport + .execute('eth_accounts') + .then((accounts) => { + expect(accounts.length).to.be.equal(1); + expect(accounts[0]).to.be.equal(ADDRESS); + }); + }); + + it('can handle `parity_defaultAccount`', () => { + return transport + .execute('parity_defaultAccount') + .then((address) => { + expect(address).to.be.equal(ADDRESS); + }); + }); + + it('can handle `parity_phraseToAddress`', () => { + return transport + .execute('parity_phraseToAddress', '') + .then((address) => { + expect(address).to.be.equal(ADDRESS); + + return transport.execute('parity_phraseToAddress', FOO_PHRASE); + }) + .then((address) => { + expect(address).to.be.equal(FOO_ADDRESS); + }); + }); + + it('can create and kill an account', () => { + return transport + .execute('parity_newAccountFromPhrase', FOO_PHRASE, FOO_PASSWORD) + .then((address) => { + expect(address).to.be.equal(FOO_ADDRESS); + + return transport.execute('eth_accounts'); + }) + .then((accounts) => { + expect(accounts.length).to.be.equal(2); + expect(accounts.includes(FOO_ADDRESS)).to.be.true; + + return transport.execute('parity_killAccount', FOO_ADDRESS, FOO_PASSWORD); + }) + .then((result) => { + expect(result).to.be.true; + + return transport.execute('eth_accounts'); + }) + .then((accounts) => { + expect(accounts.length).to.be.equal(1); + expect(accounts.includes(FOO_ADDRESS)).to.be.false; + }); + }); +}); diff --git a/js/src/api/local/transactions.js b/js/src/api/local/transactions.js index 57d1eee62..757255b4a 100644 --- a/js/src/api/local/transactions.js +++ b/js/src/api/local/transactions.js @@ -18,6 +18,7 @@ import { toHex } from '../util/format'; import { TransportError } from '../transport'; const AWAITING = Symbol('awaiting'); +const LOCKED = Symbol('locked'); const CONFIRMED = Symbol('confirmed'); const REJECTED = Symbol('rejected'); @@ -57,6 +58,16 @@ class Transactions { return state.transaction; } + lock (id) { + const state = this._states[id]; + + if (!state || state.status !== AWAITING) { + throw new Error('Trying to lock an invalid transaction'); + } + + state.status = LOCKED; + } + hash (id) { const state = this._states[id]; @@ -76,9 +87,12 @@ class Transactions { confirm (id, hash) { const state = this._states[id]; + const status = state ? state.status : null; - if (!state || state.status !== AWAITING) { - throw new Error('Trying to confirm an invalid transaction'); + switch (status) { + case AWAITING: break; + case LOCKED: break; + default: throw new Error('Trying to confirm an invalid transaction'); } state.hash = hash; diff --git a/js/src/api/local/transactions.spec.js b/js/src/api/local/transactions.spec.js index 84482ff57..65f2d8ddc 100644 --- a/js/src/api/local/transactions.spec.js +++ b/js/src/api/local/transactions.spec.js @@ -65,4 +65,21 @@ describe('api/local/transactions', () => { expect(requests.length).to.be.equal(0); expect(() => transactions.hash(id)).to.throw(TransportError); }); + + it('can lock and confirm transactions', () => { + const id = transactions.add(DUMMY_TX); + const hash = '0x1111111111111111111111111111111111111111'; + + transactions.lock(id); + + const requests = transactions.requestsToConfirm(); + + expect(requests.length).to.be.equal(0); + expect(transactions.get(id)).to.be.null; + expect(transactions.hash(id)).to.be.null; + + transactions.confirm(id, hash); + + expect(transactions.hash(id)).to.be.equal(hash); + }); }); diff --git a/js/src/api/transport/jsonRpcBase.js b/js/src/api/transport/jsonRpcBase.js index 573204c3e..819e1f496 100644 --- a/js/src/api/transport/jsonRpcBase.js +++ b/js/src/api/transport/jsonRpcBase.js @@ -38,20 +38,20 @@ export default class JsonRpcBase extends EventEmitter { return json; } - addMiddleware (middleware) { + addMiddleware (Middleware) { this._middlewareList = Promise .all([ - middleware, + Middleware, this._middlewareList ]) - .then(([middleware, middlewareList]) => { + .then(([Middleware, middlewareList]) => { // Do nothing if `handlerPromise` resolves to a null-y value. - if (middleware == null) { + if (Middleware == null) { return middlewareList; } // don't mutate the original array - return middlewareList.concat([middleware]); + return middlewareList.concat([new Middleware(this)]); }); } @@ -80,8 +80,8 @@ export default class JsonRpcBase extends EventEmitter { const res = middleware.handle(method, params); if (res != null) { - // If `res` isn't a promise, we need to wrap it - return Promise.resolve(res) + return Promise + .resolve(res) .then((res) => { const result = this._wrapSuccessResult(res); const json = this.encode(method, params); diff --git a/js/src/api/transport/middleware.js b/js/src/api/transport/middleware.js index 5a4945e7e..7d7199f95 100644 --- a/js/src/api/transport/middleware.js +++ b/js/src/api/transport/middleware.js @@ -28,9 +28,7 @@ export default class Middleware { const handler = this._handlers[method]; if (handler != null) { - const response = handler(params); - - return response; + return handler(params); } return null; diff --git a/js/src/api/transport/middleware.spec.js b/js/src/api/transport/middleware.spec.js index 27b81c49f..4ae894135 100644 --- a/js/src/api/transport/middleware.spec.js +++ b/js/src/api/transport/middleware.spec.js @@ -25,17 +25,21 @@ class MockTransport extends JsonRpcBase { } } +class MockMiddleware extends Middleware { + constructor (transport) { + super(transport); + + this.register('mock_rpc', ([num]) => num); + this.register('mock_null', () => null); + } +} + describe('api/transport/Middleware', () => { - let middleware; let transport; beforeEach(() => { transport = new MockTransport(); - middleware = new Middleware(transport); - - middleware.register('mock_rpc', ([num]) => num); - middleware.register('mock_null', () => null); - transport.addMiddleware(middleware); + transport.addMiddleware(MockMiddleware); }); it('Routes requests to middleware', () => { diff --git a/js/webpack/app.js b/js/webpack/app.js index d121b6518..ded5c4468 100644 --- a/js/webpack/app.js +++ b/js/webpack/app.js @@ -138,7 +138,9 @@ module.exports = { resolve: { alias: { - '~': path.resolve(__dirname, '../src') + '~': path.resolve(__dirname, '../src'), + 'secp256k1': path.resolve(__dirname, '../node_modules/secp256k1/js'), + 'keythereum': path.resolve(__dirname, '../node_modules/keythereum/dist/keythereum') }, modules: [ path.join(__dirname, '../node_modules') diff --git a/js/webpack/libraries.js b/js/webpack/libraries.js index 3ddd45f2c..1fcb39eba 100644 --- a/js/webpack/libraries.js +++ b/js/webpack/libraries.js @@ -41,7 +41,9 @@ module.exports = { resolve: { alias: { - '~': path.resolve(__dirname, '../src') + '~': path.resolve(__dirname, '../src'), + 'secp256k1': path.resolve(__dirname, '../node_modules/secp256k1/js'), + 'keythereum': path.resolve(__dirname, '../node_modules/keythereum/dist/keythereum') } }, diff --git a/js/webpack/npm.js b/js/webpack/npm.js index b526b2f0f..2230bf90f 100644 --- a/js/webpack/npm.js +++ b/js/webpack/npm.js @@ -76,7 +76,6 @@ module.exports = { resolve: { alias: { - 'secp256k1/js': path.resolve(__dirname, '../src/api/local/ethkey/dummy.js'), '~': path.resolve(__dirname, '../src') }, modules: [ From a45791d2c0e8d34531bb4fd9024189f252417dd0 Mon Sep 17 00:00:00 2001 From: maciejhirsz Date: Thu, 6 Apr 2017 17:36:21 +0200 Subject: [PATCH 03/29] Handle invalid passwords --- js/src/api/local/localAccountsMiddleware.js | 6 ++++++ js/src/api/local/transactions.js | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/js/src/api/local/localAccountsMiddleware.js b/js/src/api/local/localAccountsMiddleware.js index 05eefb3ca..7f01ee913 100644 --- a/js/src/api/local/localAccountsMiddleware.js +++ b/js/src/api/local/localAccountsMiddleware.js @@ -170,6 +170,12 @@ export default class LocalAccountsMiddleware extends Middleware { account.decryptPrivateKey(password) ]) .then(([nonce, privateKey]) => { + if (!privateKey) { + transactions.unlock(id); + + throw new Error('Invalid password'); + } + const tx = new EthereumTx({ nonce, to, diff --git a/js/src/api/local/transactions.js b/js/src/api/local/transactions.js index 757255b4a..421e73012 100644 --- a/js/src/api/local/transactions.js +++ b/js/src/api/local/transactions.js @@ -68,6 +68,16 @@ class Transactions { state.status = LOCKED; } + unlock (id) { + const state = this._states[id]; + + if (!state || state.status !== LOCKED) { + throw new Error('Trying to unlock an invalid transaction'); + } + + state.status = AWAITING; + } + hash (id) { const state = this._states[id]; From b11a84a3473e501bfac001eec92bafb5e8843fcf Mon Sep 17 00:00:00 2001 From: maciejhirsz Date: Mon, 10 Apr 2017 11:22:32 +0200 Subject: [PATCH 04/29] Unlock transaction on RPC errors --- js/src/api/local/localAccountsMiddleware.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/src/api/local/localAccountsMiddleware.js b/js/src/api/local/localAccountsMiddleware.js index 7f01ee913..753de8a4c 100644 --- a/js/src/api/local/localAccountsMiddleware.js +++ b/js/src/api/local/localAccountsMiddleware.js @@ -169,6 +169,12 @@ export default class LocalAccountsMiddleware extends Middleware { this.rpcRequest('parity_nextNonce', [from]), account.decryptPrivateKey(password) ]) + .catch((err) => { + transactions.unlock(id); + + // transaction got unlocked, can propagate rejection further + throw err; + }) .then(([nonce, privateKey]) => { if (!privateKey) { transactions.unlock(id); From cc6cf8d7cea673ac5aa1b952c3e384bbabe83b04 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 10 Apr 2017 18:06:36 +0200 Subject: [PATCH 05/29] address grumble --- rpc/src/v1/helpers/light_fetch.rs | 4 ++-- rpc/src/v1/impls/parity.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index e2ce6880f..bcd97d2c5 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -36,7 +36,7 @@ use light::on_demand::{OnDemand, request}; use ethsync::LightSync; use util::{Address, Mutex, Uint, U256}; -use v1::helpers::{CallRequest as CRequest, errors, dispatch}; +use v1::helpers::{CallRequest as CallRequestHelper, errors, dispatch}; use v1::types::{BlockNumber, CallRequest}; /// Helper for fetching blockchain data either from the light client or the network @@ -130,7 +130,7 @@ impl LightFetch { const DEFAULT_GAS_PRICE: U256 = U256([0, 0, 0, 21_000_000]); let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone()); - let req: CRequest = req.into(); + let req: CallRequestHelper = req.into(); let id = num.0.into(); let from = req.from.unwrap_or(Address::zero()); diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 641cab39d..78592a91c 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -427,6 +427,7 @@ impl Parity for ParityClient where }, extra_info: client.block_extra_info(id).expect(EXTRA_INFO_PROOF), })).boxed() + } fn ipfs_cid(&self, content: Bytes) -> Result { ipfs::cid(content) From bb8adcce9255770a3523b907ffbe8682b9232f31 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 11 Apr 2017 16:43:15 +0200 Subject: [PATCH 06/29] Work around mismatch for QR checksum (#5374) * Work around current native-signer encoding * Avoid trying to use non-existant util function. --- js/src/i18n/zh/writeContract.js | 2 +- js/src/modals/CreateAccount/store.js | 6 +++++- js/src/views/WriteContract/writeContract.js | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/js/src/i18n/zh/writeContract.js b/js/src/i18n/zh/writeContract.js index fc1100b77..62f83dd4d 100644 --- a/js/src/i18n/zh/writeContract.js +++ b/js/src/i18n/zh/writeContract.js @@ -37,7 +37,7 @@ export default { params: `An error occurred with the following description` }, input: { - abi: `ABI Interface`, + abi: `ABI Definition`, code: `Bytecode`, metadata: `Metadata`, swarm: `Swarm Metadata Hash` diff --git a/js/src/modals/CreateAccount/store.js b/js/src/modals/CreateAccount/store.js index 9bc60d9af..9f78360fa 100644 --- a/js/src/modals/CreateAccount/store.js +++ b/js/src/modals/CreateAccount/store.js @@ -96,6 +96,7 @@ export default class Store { } @computed get qrAddressValid () { + console.log('qrValid', this.qrAddress, this._api.util.isAddressValid(this.qrAddress)); return this._api.util.isAddressValid(this.qrAddress); } @@ -155,7 +156,10 @@ export default class Store { qrAddress = `0x${qrAddress}`; } - this.qrAddress = qrAddress; + // FIXME: Current native signer encoding is not 100% for EIP-55, lowercase for now + this.qrAddress = this._api.util + ? this._api.util.toChecksumAddress(qrAddress.toLowerCase()) + : qrAddress; } @action setVaultName = (vaultName) => { diff --git a/js/src/views/WriteContract/writeContract.js b/js/src/views/WriteContract/writeContract.js index 86262820d..170c0d7c1 100644 --- a/js/src/views/WriteContract/writeContract.js +++ b/js/src/views/WriteContract/writeContract.js @@ -608,7 +608,7 @@ class WriteContract extends Component { label={ } readOnly From e84d03f31d80a5b6b674371a852c56b6a1343c1c Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Tue, 11 Apr 2017 15:08:42 +0000 Subject: [PATCH 07/29] [ci skip] js-precompiled 20170411-150514 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 830e1e75a..8f710cc18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1761,7 +1761,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#b4c41885c6e02c64fb773546b2f135f56ea7022f" +source = "git+https://github.com/paritytech/js-precompiled.git#f4fa3048dcb0e202c53a61b9b9e7dd446fa1c088" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 56806ef41..e4bf27430 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.49", + "version": "1.7.50", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From daf1495c4efe9b4aecc9adab1494f4f8b5acd1e5 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 12 Apr 2017 12:07:54 +0200 Subject: [PATCH 08/29] Filters and block RPCs for the light client (#5320) * block_hash method for LightChainClient * abstraction and futures-based eth_filter * log fetching for light client * add eth-filter delegate * eth_block fetching RPCs * return default accounts from on_demand * fix early exit * BlockNumber -> BlockId * early exit for no known block number. --- ethcore/light/src/client/header_chain.rs | 38 ++++ ethcore/light/src/client/mod.rs | 26 ++- ethcore/light/src/on_demand/mod.rs | 27 ++- ethcore/src/types/encoded.rs | 6 + parity/light_helpers/queue_cull.rs | 4 +- parity/rpc_apis.rs | 7 +- parity/run.rs | 3 +- rpc/src/v1/helpers/dispatch.rs | 2 +- rpc/src/v1/impls/eth.rs | 10 +- rpc/src/v1/impls/eth_filter.rs | 174 +++++++++++------ rpc/src/v1/impls/light/eth.rs | 239 +++++++++++++++++++++-- rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/traits/eth.rs | 12 +- 13 files changed, 442 insertions(+), 108 deletions(-) diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index fe3c86aad..35e6d996c 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -361,6 +361,22 @@ impl HeaderChain { } } + /// Get a block's hash by ID. In the case of query by number, only canonical results + /// will be returned. + pub fn block_hash(&self, id: BlockId) -> Option { + match id { + BlockId::Earliest => Some(self.genesis_hash()), + BlockId::Hash(hash) => Some(hash), + BlockId::Number(num) => { + if self.best_block.read().number < num { return None } + self.candidates.read().get(&num).map(|entry| entry.canonical_hash) + } + BlockId::Latest | BlockId::Pending => { + Some(self.best_block.read().hash) + } + } + } + /// Get a block header. In the case of query by number, only canonical blocks /// will be returned. pub fn block_header(&self, id: BlockId) -> Option { @@ -414,6 +430,28 @@ impl HeaderChain { } } + /// Get a block's chain score. + /// Returns nothing for non-canonical blocks. + pub fn score(&self, id: BlockId) -> Option { + let genesis_hash = self.genesis_hash(); + match id { + BlockId::Earliest | BlockId::Number(0) => Some(self.genesis_header.difficulty()), + BlockId::Hash(hash) if hash == genesis_hash => Some(self.genesis_header.difficulty()), + BlockId::Hash(hash) => match self.block_header(BlockId::Hash(hash)) { + Some(header) => self.candidates.read().get(&header.number()) + .and_then(|era| era.candidates.iter().find(|e| e.hash == hash)) + .map(|c| c.total_difficulty), + None => None, + }, + BlockId::Number(num) => { + let candidates = self.candidates.read(); + if self.best_block.read().number < num { return None } + candidates.get(&num).map(|era| era.candidates[0].total_difficulty) + } + BlockId::Latest | BlockId::Pending => Some(self.best_block.read().total_difficulty) + } + } + /// Get the best block's header. pub fn best_header(&self) -> encoded::Header { self.block_header(BlockId::Latest).expect("Header for best block always stored; qed") diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 5424d5d1a..9e2257930 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -31,7 +31,7 @@ use ethcore::service::ClientIoMessage; use ethcore::encoded; use io::IoChannel; -use util::{H256, Mutex, RwLock}; +use util::{H256, U256, Mutex, RwLock}; use util::kvdb::{KeyValueDB, CompactionProfile}; use self::header_chain::{AncestryIter, HeaderChain}; @@ -67,12 +67,18 @@ pub trait LightChainClient: Send + Sync { /// parent queued prior. fn queue_header(&self, header: Header) -> Result; + /// Attempt to get a block hash by block id. + fn block_hash(&self, id: BlockId) -> Option; + /// Attempt to get block header by block id. fn block_header(&self, id: BlockId) -> Option; /// Get the best block header. fn best_block_header(&self) -> encoded::Header; + /// Get a block's chain score by ID. + fn score(&self, id: BlockId) -> Option; + /// Get an iterator over a block and its ancestry. fn ancestry_iter<'a>(&'a self, start: BlockId) -> Box + 'a>; @@ -183,6 +189,11 @@ impl Client { self.queue.queue_info() } + /// Attempt to get a block hash by block id. + pub fn block_hash(&self, id: BlockId) -> Option { + self.chain.block_hash(id) + } + /// Get a block header by Id. pub fn block_header(&self, id: BlockId) -> Option { self.chain.block_header(id) @@ -193,6 +204,11 @@ impl Client { self.chain.best_header() } + /// Get a block's chain score. + pub fn score(&self, id: BlockId) -> Option { + self.chain.score(id) + } + /// Get an iterator over a block and its ancestry. pub fn ancestry_iter(&self, start: BlockId) -> AncestryIter { self.chain.ancestry_iter(start) @@ -310,6 +326,10 @@ impl LightChainClient for Client { self.import_header(header) } + fn block_hash(&self, id: BlockId) -> Option { + Client::block_hash(self, id) + } + fn block_header(&self, id: BlockId) -> Option { Client::block_header(self, id) } @@ -318,6 +338,10 @@ impl LightChainClient for Client { Client::best_block_header(self) } + fn score(&self, id: BlockId) -> Option { + Client::score(self, id) + } + fn ancestry_iter<'a>(&'a self, start: BlockId) -> Box + 'a> { Box::new(Client::ancestry_iter(self, start)) } diff --git a/ethcore/light/src/on_demand/mod.rs b/ethcore/light/src/on_demand/mod.rs index a7c1ba2c4..c756844c9 100644 --- a/ethcore/light/src/on_demand/mod.rs +++ b/ethcore/light/src/on_demand/mod.rs @@ -35,7 +35,7 @@ use futures::sync::oneshot::{self, Sender, Receiver}; use network::PeerId; use rlp::RlpStream; use util::{Bytes, RwLock, Mutex, U256, H256}; -use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP}; +use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY, SHA3_EMPTY_LIST_RLP}; use net::{self, Handler, Status, Capabilities, Announcement, EventContext, BasicContext, ReqId}; use cache::Cache; @@ -83,7 +83,7 @@ enum Pending { HeaderByHash(request::HeaderByHash, Sender), Block(request::Body, Sender), BlockReceipts(request::BlockReceipts, Sender>), - Account(request::Account, Sender>), + Account(request::Account, Sender), Code(request::Code, Sender), TxProof(request::TransactionProof, Sender>), } @@ -136,18 +136,20 @@ pub struct OnDemand { pending_requests: RwLock>, cache: Arc>, orphaned_requests: RwLock>, + start_nonce: U256, } const RECEIVER_IN_SCOPE: &'static str = "Receiver is still in scope, so it's not dropped; qed"; impl OnDemand { /// Create a new `OnDemand` service with the given cache. - pub fn new(cache: Arc>) -> Self { + pub fn new(cache: Arc>, account_start_nonce: U256) -> Self { OnDemand { peers: RwLock::new(HashMap::new()), pending_requests: RwLock::new(HashMap::new()), cache: cache, orphaned_requests: RwLock::new(Vec::new()), + start_nonce: account_start_nonce, } } @@ -268,7 +270,7 @@ impl OnDemand { /// Request an account by address and block header -- which gives a hash to query and a state root /// to verify against. - pub fn account(&self, ctx: &BasicContext, req: request::Account) -> Receiver> { + pub fn account(&self, ctx: &BasicContext, req: request::Account) -> Receiver { let (sender, receiver) = oneshot::channel(); self.dispatch(ctx, Pending::Account(req, sender)); receiver @@ -279,7 +281,7 @@ impl OnDemand { let (sender, receiver) = oneshot::channel(); // fast path for no code. - if req.code_hash == ::util::sha3::SHA3_EMPTY { + if req.code_hash == SHA3_EMPTY { sender.send(Vec::new()).expect(RECEIVER_IN_SCOPE) } else { self.dispatch(ctx, Pending::Code(req, sender)); @@ -497,10 +499,19 @@ impl Handler for OnDemand { Pending::Account(req, sender) => { if let NetworkResponse::Account(ref response) = *response { match req.check_response(&response.proof) { - Ok(maybe_account) => { + Ok(account) => { + let account = account.unwrap_or_else(|| { + BasicAccount { + balance: 0.into(), + nonce: self.start_nonce, + code_hash: SHA3_EMPTY, + storage_root: SHA3_NULL_RLP + } + }); + // TODO: validate against request outputs. // needs engine + env info as part of request. - let _ = sender.send(maybe_account); + let _ = sender.send(account); return } Err(e) => warn!(target: "on_demand", "Error handling response for state request: {:?}", e), @@ -572,7 +583,7 @@ mod tests { #[test] fn detects_hangup() { let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); - let on_demand = OnDemand::new(cache); + let on_demand = OnDemand::new(cache, 0.into()); let result = on_demand.header_by_hash(&FakeContext, request::HeaderByHash(H256::default())); assert!(on_demand.orphaned_requests.read().len() == 1); diff --git a/ethcore/src/types/encoded.rs b/ethcore/src/types/encoded.rs index 0a4164044..125a00fd0 100644 --- a/ethcore/src/types/encoded.rs +++ b/ethcore/src/types/encoded.rs @@ -199,6 +199,12 @@ impl Block { /// Decode to a full block. pub fn decode(&self) -> FullBlock { ::rlp::decode(&self.0) } + /// Decode the header. + pub fn decode_header(&self) -> FullHeader { self.rlp().val_at(0) } + + /// Clone the encoded header. + pub fn header(&self) -> Header { Header(self.rlp().at(0).as_raw().to_vec()) } + /// Get the rlp of this block. #[inline] pub fn rlp(&self) -> Rlp { diff --git a/parity/light_helpers/queue_cull.rs b/parity/light_helpers/queue_cull.rs index 10865d485..548ee33cd 100644 --- a/parity/light_helpers/queue_cull.rs +++ b/parity/light_helpers/queue_cull.rs @@ -67,7 +67,6 @@ impl IoHandler for QueueCull { let (sync, on_demand, txq) = (self.sync.clone(), self.on_demand.clone(), self.txq.clone()); let best_header = self.client.best_block_header(); - let start_nonce = self.client.engine().account_start_nonce(); info!(target: "cull", "Attempting to cull queued transactions from {} senders.", senders.len()); self.remote.spawn_with_timeout(move || { @@ -75,8 +74,7 @@ impl IoHandler for QueueCull { // fetch the nonce of each sender in the queue. let nonce_futures = senders.iter() .map(|&address| request::Account { header: best_header.clone(), address: address }) - .map(|request| on_demand.account(ctx, request)) - .map(move |fut| fut.map(move |x| x.map(|acc| acc.nonce).unwrap_or(start_nonce))) + .map(|request| on_demand.account(ctx, request).map(|acc| acc.nonce)) .zip(senders.iter()) .map(|(fut, &addr)| fut.map(move |nonce| (addr, nonce))); diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index cf3c0b7c9..538808909 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -244,7 +244,7 @@ impl Dependencies for FullDependencies { ); handler.extend_with(client.to_delegate()); - let filter_client = EthFilterClient::new(&self.client, &self.miner); + let filter_client = EthFilterClient::new(self.client.clone(), self.miner.clone()); handler.extend_with(filter_client.to_delegate()); add_signing_methods!(EthSigning, handler, self); @@ -377,9 +377,8 @@ impl Dependencies for LightDependencies { self.secret_store.clone(), self.cache.clone(), ); - handler.extend_with(client.to_delegate()); - - // TODO: filters. + handler.extend_with(Eth::to_delegate(client.clone())); + handler.extend_with(EthFilter::to_delegate(client)); add_signing_methods!(EthSigning, handler, self); }, Api::Personal => { diff --git a/parity/run.rs b/parity/run.rs index c6086d6b8..70a23f934 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -221,7 +221,8 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc) -> } // start on_demand service. - let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone())); + let account_start_nonce = service.client().engine().account_start_nonce(); + let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone(), account_start_nonce)); // set network path. net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index e1b298b9f..d58a211ed 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -268,7 +268,7 @@ impl LightDispatcher { match nonce_future { Some(x) => - x.map(|acc| acc.map_or_else(Default::default, |acc| acc.nonce)) + x.map(|acc| acc.nonce) .map_err(|_| errors::no_light_peers()) .boxed(), None => future::err(errors::network_disabled()).boxed() diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 73d4d9f9b..01d624e97 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -544,23 +544,23 @@ impl Eth for EthClient where Err(errors::deprecated("Compilation functionality is deprecated.".to_string())) } - fn logs(&self, filter: Filter) -> Result, Error> { + fn logs(&self, filter: Filter) -> BoxFuture, Error> { let include_pending = filter.to_block == Some(BlockNumber::Pending); let filter: EthcoreFilter = filter.into(); - let mut logs = take_weak!(self.client).logs(filter.clone()) + let mut logs = take_weakf!(self.client).logs(filter.clone()) .into_iter() .map(From::from) .collect::>(); if include_pending { - let best_block = take_weak!(self.client).chain_info().best_block_number; - let pending = pending_logs(&*take_weak!(self.miner), best_block, &filter); + let best_block = take_weakf!(self.client).chain_info().best_block_number; + let pending = pending_logs(&*take_weakf!(self.miner), best_block, &filter); logs.extend(pending); } let logs = limit_logs(logs, filter.limit); - Ok(logs) + future::ok(logs).boxed() } fn work(&self, no_new_work_timeout: Trailing) -> Result { diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index cf3398498..8f448feb5 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -16,89 +16,133 @@ //! Eth Filter RPC implementation -use std::sync::{Arc, Weak}; +use std::sync::Arc; use std::collections::HashSet; + use jsonrpc_core::*; use ethcore::miner::MinerService; use ethcore::filter::Filter as EthcoreFilter; use ethcore::client::{BlockChainClient, BlockId}; -use util::Mutex; +use util::{H256, Mutex}; + +use futures::{future, Future, BoxFuture}; + use v1::traits::EthFilter; use v1::types::{BlockNumber, Index, Filter, FilterChanges, Log, H256 as RpcH256, U256 as RpcU256}; use v1::helpers::{PollFilter, PollManager, limit_logs}; use v1::impls::eth::pending_logs; -/// Eth filter rpc implementation. +/// Something which provides data that can be filtered over. +pub trait Filterable { + /// Current best block number. + fn best_block_number(&self) -> u64; + + /// Get a block hash by block id. + fn block_hash(&self, id: BlockId) -> Option; + + /// pending transaction hashes at the given block. + fn pending_transactions_hashes(&self, block_number: u64) -> Vec; + + /// Get logs that match the given filter. + fn logs(&self, filter: EthcoreFilter) -> BoxFuture, Error>; + + /// Get logs from the pending block. + fn pending_logs(&self, block_number: u64, filter: &EthcoreFilter) -> Vec; + + /// Get a reference to the poll manager. + fn polls(&self) -> &Mutex>; +} + +/// Eth filter rpc implementation for a full node. pub struct EthFilterClient where C: BlockChainClient, M: MinerService { - client: Weak, - miner: Weak, + client: Arc, + miner: Arc, polls: Mutex>, } -impl EthFilterClient where - C: BlockChainClient, - M: MinerService { - +impl EthFilterClient where C: BlockChainClient, M: MinerService { /// Creates new Eth filter client. - pub fn new(client: &Arc, miner: &Arc) -> Self { + pub fn new(client: Arc, miner: Arc) -> Self { EthFilterClient { - client: Arc::downgrade(client), - miner: Arc::downgrade(miner), + client: client, + miner: miner, polls: Mutex::new(PollManager::new()), } } } -impl EthFilter for EthFilterClient - where C: BlockChainClient + 'static, M: MinerService + 'static -{ +impl Filterable for EthFilterClient where C: BlockChainClient, M: MinerService { + fn best_block_number(&self) -> u64 { + self.client.chain_info().best_block_number + } + + fn block_hash(&self, id: BlockId) -> Option { + self.client.block_hash(id).map(Into::into) + } + + fn pending_transactions_hashes(&self, best: u64) -> Vec { + self.miner.pending_transactions_hashes(best) + } + + fn logs(&self, filter: EthcoreFilter) -> BoxFuture, Error> { + future::ok(self.client.logs(filter).into_iter().map(Into::into).collect()).boxed() + } + + fn pending_logs(&self, block_number: u64, filter: &EthcoreFilter) -> Vec { + pending_logs(&*self.miner, block_number, filter) + } + + fn polls(&self) -> &Mutex> { &self.polls } +} + + + +impl EthFilter for T { fn new_filter(&self, filter: Filter) -> Result { - let mut polls = self.polls.lock(); - let block_number = take_weak!(self.client).chain_info().best_block_number; + let mut polls = self.polls().lock(); + let block_number = self.best_block_number(); let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter)); Ok(id.into()) } fn new_block_filter(&self) -> Result { - let mut polls = self.polls.lock(); - let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); + let mut polls = self.polls().lock(); + let id = polls.create_poll(PollFilter::Block(self.best_block_number())); Ok(id.into()) } fn new_pending_transaction_filter(&self) -> Result { - let mut polls = self.polls.lock(); - let best_block = take_weak!(self.client).chain_info().best_block_number; - let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(best_block); + let mut polls = self.polls().lock(); + let best_block = self.best_block_number(); + let pending_transactions = self.pending_transactions_hashes(best_block); let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); Ok(id.into()) } - fn filter_changes(&self, index: Index) -> Result { - let client = take_weak!(self.client); - let mut polls = self.polls.lock(); + fn filter_changes(&self, index: Index) -> BoxFuture { + let mut polls = self.polls().lock(); match polls.poll_mut(&index.value()) { - None => Ok(FilterChanges::Empty), + None => future::ok(FilterChanges::Empty).boxed(), Some(filter) => match *filter { PollFilter::Block(ref mut block_number) => { // + 1, cause we want to return hashes including current block hash. - let current_number = client.chain_info().best_block_number + 1; + let current_number = self.best_block_number() + 1; let hashes = (*block_number..current_number).into_iter() .map(BlockId::Number) - .filter_map(|id| client.block_hash(id)) - .map(Into::into) + .filter_map(|id| self.block_hash(id)) .collect::>(); *block_number = current_number; - Ok(FilterChanges::Hashes(hashes)) + future::ok(FilterChanges::Hashes(hashes)).boxed() }, PollFilter::PendingTransaction(ref mut previous_hashes) => { // get hashes of pending transactions - let best_block = take_weak!(self.client).chain_info().best_block_number; - let current_hashes = take_weak!(self.miner).pending_transactions_hashes(best_block); + let best_block = self.best_block_number(); + let current_hashes = self.pending_transactions_hashes(best_block); let new_hashes = { @@ -117,11 +161,11 @@ impl EthFilter for EthFilterClient *previous_hashes = current_hashes; // return new hashes - Ok(FilterChanges::Hashes(new_hashes)) + future::ok(FilterChanges::Hashes(new_hashes)).boxed() }, PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => { // retrive the current block number - let current_number = client.chain_info().best_block_number; + let current_number = self.best_block_number(); // check if we need to check pending hashes let include_pending = filter.to_block == Some(BlockNumber::Pending); @@ -131,16 +175,9 @@ impl EthFilter for EthFilterClient filter.from_block = BlockId::Number(*block_number); filter.to_block = BlockId::Latest; - // retrieve logs in range from_block..min(BlockId::Latest..to_block) - let mut logs = client.logs(filter.clone()) - .into_iter() - .map(From::from) - .collect::>(); - - // additionally retrieve pending logs - if include_pending { - let best_block = take_weak!(self.client).chain_info().best_block_number; - let pending_logs = pending_logs(&*take_weak!(self.miner), best_block, &filter); + // retrieve pending logs + let pending = if include_pending { + let pending_logs = self.pending_logs(current_number, &filter); // remove logs about which client was already notified about let new_pending_logs: Vec<_> = pending_logs.iter() @@ -151,49 +188,56 @@ impl EthFilter for EthFilterClient // save all logs retrieved by client *previous_logs = pending_logs.into_iter().collect(); - // append logs array with new pending logs - logs.extend(new_pending_logs); - } - - let logs = limit_logs(logs, filter.limit); + new_pending_logs + } else { + Vec::new() + }; // save the number of the next block as a first block from which // we want to get logs *block_number = current_number + 1; - Ok(FilterChanges::Logs(logs)) + // retrieve logs in range from_block..min(BlockId::Latest..to_block) + let limit = filter.limit; + self.logs(filter) + .map(move |mut logs| { logs.extend(pending); logs }) // append fetched pending logs + .map(move |logs| limit_logs(logs, limit)) // limit the logs + .map(FilterChanges::Logs) + .boxed() } } } } - fn filter_logs(&self, index: Index) -> Result, Error> { - let mut polls = self.polls.lock(); + fn filter_logs(&self, index: Index) -> BoxFuture, Error> { + let mut polls = self.polls().lock(); match polls.poll(&index.value()) { Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => { let include_pending = filter.to_block == Some(BlockNumber::Pending); let filter: EthcoreFilter = filter.clone().into(); - let mut logs = take_weak!(self.client).logs(filter.clone()) - .into_iter() - .map(From::from) - .collect::>(); - if include_pending { - let best_block = take_weak!(self.client).chain_info().best_block_number; - logs.extend(pending_logs(&*take_weak!(self.miner), best_block, &filter)); - } + // fetch pending logs. + let pending = if include_pending { + let best_block = self.best_block_number(); + self.pending_logs(best_block, &filter) + } else { + Vec::new() + }; - let logs = limit_logs(logs, filter.limit); - - Ok(logs) + // retrieve logs asynchronously, appending pending logs. + let limit = filter.limit; + self.logs(filter) + .map(move |mut logs| { logs.extend(pending); logs }) + .map(move |logs| limit_logs(logs, limit)) + .boxed() }, // just empty array - _ => Ok(Vec::new()), + _ => future::ok(Vec::new()).boxed() } } fn uninstall_filter(&self, index: Index) -> Result { - self.polls.lock().remove_poll(&index.value()); + self.polls().lock().remove_poll(&index.value()); Ok(true) } } diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 1851f479e..d388e922a 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -34,6 +34,7 @@ use ethcore::basic_account::BasicAccount; use ethcore::encoded; use ethcore::executed::{Executed, ExecutionError}; use ethcore::ids::BlockId; +use ethcore::filter::Filter as EthcoreFilter; use ethcore::transaction::{Action, SignedTransaction, Transaction as EthTransaction}; use ethsync::LightSync; use rlp::UntrustedRlp; @@ -43,7 +44,9 @@ use util::{RwLock, Mutex, Uint, U256}; use futures::{future, Future, BoxFuture, IntoFuture}; use futures::sync::oneshot; +use v1::impls::eth_filter::Filterable; use v1::helpers::{CallRequest as CRequest, errors, limit_logs, dispatch}; +use v1::helpers::{PollFilter, PollManager}; use v1::helpers::block_import::is_major_importing; use v1::traits::Eth; use v1::types::{ @@ -55,7 +58,7 @@ use v1::metadata::Metadata; use util::Address; -/// Light client `ETH` RPC. +/// Light client `ETH` (and filter) RPC. pub struct EthClient { sync: Arc, client: Arc, @@ -63,6 +66,22 @@ pub struct EthClient { transaction_queue: Arc>, accounts: Arc, cache: Arc>, + polls: Mutex>, +} + +impl Clone for EthClient { + fn clone(&self) -> Self { + // each instance should have its own poll manager. + EthClient { + sync: self.sync.clone(), + client: self.client.clone(), + on_demand: self.on_demand.clone(), + transaction_queue: self.transaction_queue.clone(), + accounts: self.accounts.clone(), + cache: self.cache.clone(), + polls: Mutex::new(PollManager::new()), + } + } } // helper for internal error: on demand sender cancelled. @@ -90,6 +109,7 @@ impl EthClient { transaction_queue: transaction_queue, accounts: accounts, cache: cache, + polls: Mutex::new(PollManager::new()), } } @@ -153,12 +173,15 @@ impl EthClient { Some(hdr) => hdr, }; - sync.with_context(|ctx| on_demand.account(ctx, request::Account { + let maybe_fut = sync.with_context(|ctx| on_demand.account(ctx, request::Account { header: header, address: address, - })) - .map(|x| x.map_err(err_premature_cancel).boxed()) - .unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) + })); + + match maybe_fut { + Some(fut) => fut.map(Some).map_err(err_premature_cancel).boxed(), + None => future::err(errors::network_disabled()).boxed(), + } }).boxed() } @@ -234,6 +257,111 @@ impl EthClient { } }).boxed() } + + fn block(&self, id: BlockId) -> BoxFuture, Error> { + let (on_demand, sync) = (self.on_demand.clone(), self.sync.clone()); + + self.header(id).and_then(move |hdr| { + let req = match hdr { + Some(hdr) => request::Body::new(hdr), + None => return future::ok(None).boxed(), + }; + + match sync.with_context(move |ctx| on_demand.block(ctx, req)) { + Some(fut) => fut.map_err(err_premature_cancel).map(Some).boxed(), + None => future::err(errors::network_disabled()).boxed(), + } + }).boxed() + } + + // get a "rich" block structure + fn rich_block(&self, id: BlockId, include_txs: bool) -> BoxFuture, Error> { + let (on_demand, sync) = (self.on_demand.clone(), self.sync.clone()); + let (client, engine) = (self.client.clone(), self.client.engine().clone()); + + // helper for filling out a rich block once we've got a block and a score. + let fill_rich = move |block: encoded::Block, score: Option| { + let header = block.decode_header(); + let extra_info = engine.extra_info(&header); + RichBlock { + block: Block { + hash: Some(header.hash().into()), + size: Some(block.rlp().as_raw().len().into()), + parent_hash: header.parent_hash().clone().into(), + uncles_hash: header.uncles_hash().clone().into(), + author: header.author().clone().into(), + miner: header.author().clone().into(), + state_root: header.state_root().clone().into(), + transactions_root: header.transactions_root().clone().into(), + receipts_root: header.receipts_root().clone().into(), + number: Some(header.number().into()), + gas_used: header.gas_used().clone().into(), + gas_limit: header.gas_limit().clone().into(), + logs_bloom: header.log_bloom().clone().into(), + timestamp: header.timestamp().into(), + difficulty: header.difficulty().clone().into(), + total_difficulty: score.map(Into::into), + seal_fields: header.seal().into_iter().cloned().map(Into::into).collect(), + uncles: block.uncle_hashes().into_iter().map(Into::into).collect(), + transactions: match include_txs { + true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(Into::into).collect()), + false => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()), + }, + extra_data: Bytes::new(header.extra_data().to_vec()), + }, + extra_info: extra_info + } + }; + + // get the block itself. + self.block(id).and_then(move |block| match block { + None => return future::ok(None).boxed(), + Some(block) => { + // then fetch the total difficulty (this is much easier after getting the block). + match client.score(id) { + Some(score) => future::ok(fill_rich(block, Some(score))).map(Some).boxed(), + None => { + // make a CHT request to fetch the chain score. + let req = cht::block_to_cht_number(block.number()) + .and_then(|num| client.cht_root(num as usize)) + .and_then(|root| request::HeaderProof::new(block.number(), root)); + + + let req = match req { + Some(req) => req, + None => { + // somehow the genesis block slipped past other checks. + // return it now. + let score = client.block_header(BlockId::Number(0)) + .expect("genesis always stored; qed") + .difficulty(); + + return future::ok(fill_rich(block, Some(score))).map(Some).boxed() + } + }; + + // three possible outcomes: + // - network is down. + // - we get a score, but our hash is non-canonical. + // - we get ascore, and our hash is canonical. + let maybe_fut = sync.with_context(move |ctx| on_demand.hash_and_score_by_number(ctx, req)); + match maybe_fut { + Some(fut) => fut.map(move |(hash, score)| { + let score = if hash == block.hash() { + Some(score) + } else { + None + }; + + Some(fill_rich(block, score)) + }).map_err(err_premature_cancel).boxed(), + None => return future::err(errors::network_disabled()).boxed(), + } + } + } + } + }).boxed() + } } impl Eth for EthClient { @@ -275,7 +403,10 @@ impl Eth for EthClient { } fn gas_price(&self) -> Result { - Ok(Default::default()) + Ok(self.cache.lock().gas_price_corpus() + .and_then(|c| c.median().cloned()) + .map(RpcU256::from) + .unwrap_or_else(Default::default)) } fn accounts(&self, meta: Metadata) -> BoxFuture, Error> { @@ -304,11 +435,11 @@ impl Eth for EthClient { } fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> BoxFuture, Error> { - future::err(errors::unimplemented(None)).boxed() + self.rich_block(BlockId::Hash(hash.into()), include_txs) } fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture, Error> { - future::err(errors::unimplemented(None)).boxed() + self.rich_block(num.into(), include_txs) } fn transaction_count(&self, address: RpcH160, num: Trailing) -> BoxFuture { @@ -484,19 +615,101 @@ impl Eth for EthClient { Err(errors::deprecated("Compilation of Solidity via RPC is deprecated".to_string())) } - fn logs(&self, _filter: Filter) -> Result, Error> { - Err(errors::unimplemented(None)) + fn logs(&self, filter: Filter) -> BoxFuture, Error> { + let limit = filter.limit; + + Filterable::logs(self, filter.into()) + .map(move|logs| limit_logs(logs, limit)) + .boxed() } fn work(&self, _timeout: Trailing) -> Result { - Err(errors::unimplemented(None)) + Err(errors::light_unimplemented(None)) } fn submit_work(&self, _nonce: RpcH64, _pow_hash: RpcH256, _mix_hash: RpcH256) -> Result { - Err(errors::unimplemented(None)) + Err(errors::light_unimplemented(None)) } fn submit_hashrate(&self, _rate: RpcU256, _id: RpcH256) -> Result { - Err(errors::unimplemented(None)) + Err(errors::light_unimplemented(None)) + } +} + +// This trait implementation triggers a blanked impl of `EthFilter`. +impl Filterable for EthClient { + fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number } + + fn block_hash(&self, id: BlockId) -> Option { + self.client.block_hash(id).map(Into::into) + } + + fn pending_transactions_hashes(&self, _block_number: u64) -> Vec<::util::H256> { + Vec::new() + } + + fn logs(&self, filter: EthcoreFilter) -> BoxFuture, Error> { + use std::collections::BTreeMap; + + use futures::stream::{self, Stream}; + use util::H2048; + + // early exit for "to" block before "from" block. + let best_number = self.client.chain_info().best_block_number; + let block_number = |id| match id { + BlockId::Earliest => Some(0), + BlockId::Latest | BlockId::Pending => Some(best_number), + BlockId::Hash(h) => self.client.block_header(BlockId::Hash(h)).map(|hdr| hdr.number()), + BlockId::Number(x) => Some(x), + }; + + match (block_number(filter.to_block), block_number(filter.from_block)) { + (Some(to), Some(from)) if to < from => return future::ok(Vec::new()).boxed(), + (Some(_), Some(_)) => {}, + _ => return future::err(errors::unknown_block()).boxed(), + } + + let maybe_future = self.sync.with_context(move |ctx| { + // find all headers which match the filter, and fetch the receipts for each one. + // match them with their numbers for easy sorting later. + let bit_combos = filter.bloom_possibilities(); + let receipts_futures: Vec<_> = self.client.ancestry_iter(filter.to_block) + .take_while(|ref hdr| BlockId::Number(hdr.number()) != filter.from_block) + .take_while(|ref hdr| BlockId::Hash(hdr.hash()) != filter.from_block) + .filter(|ref hdr| { + let hdr_bloom = hdr.log_bloom(); + bit_combos.iter().find(|&bloom| hdr_bloom & *bloom == *bloom).is_some() + }) + .map(|hdr| (hdr.number(), request::BlockReceipts(hdr))) + .map(|(num, req)| self.on_demand.block_receipts(ctx, req).map(move |x| (num, x))) + .collect(); + + // as the receipts come in, find logs within them which match the filter. + // insert them into a BTreeMap to maintain order by number and block index. + stream::futures_unordered(receipts_futures) + .fold(BTreeMap::new(), move |mut matches, (num, receipts)| { + for (block_index, log) in receipts.into_iter().flat_map(|r| r.logs).enumerate() { + if filter.matches(&log) { + matches.insert((num, block_index), log.into()); + } + } + future::ok(matches) + }) // and then collect them into a vector. + .map(|matches| matches.into_iter().map(|(_, v)| v).collect()) + .map_err(err_premature_cancel) + }); + + match maybe_future { + Some(fut) => fut.boxed(), + None => future::err(errors::network_disabled()).boxed(), + } + } + + fn pending_logs(&self, _block_number: u64, _filter: &EthcoreFilter) -> Vec { + Vec::new() // light clients don't mine. + } + + fn polls(&self) -> &Mutex> { + &self.polls } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index ed312c363..e8cec8eab 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -90,7 +90,7 @@ impl EthTester { let hashrates = Arc::new(Mutex::new(HashMap::new())); let external_miner = Arc::new(ExternalMiner::new(hashrates.clone())); let eth = EthClient::new(&client, &snapshot, &sync, &opt_ap, &miner, &external_miner, options).to_delegate(); - let filter = EthFilterClient::new(&client, &miner).to_delegate(); + let filter = EthFilterClient::new(client.clone(), miner.clone()).to_delegate(); let dispatcher = FullDispatcher::new(Arc::downgrade(&client), Arc::downgrade(&miner)); let sign = SigningUnsafeClient::new(&opt_ap, dispatcher).to_delegate(); diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 365ad9320..941263335 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -162,8 +162,8 @@ build_rpc_trait! { fn compile_serpent(&self, String) -> Result; /// Returns logs matching given filter object. - #[rpc(name = "eth_getLogs")] - fn logs(&self, Filter) -> Result, Error>; + #[rpc(async, name = "eth_getLogs")] + fn logs(&self, Filter) -> BoxFuture, Error>; /// Returns the hash of the current block, the seedHash, and the boundary condition to be met. #[rpc(name = "eth_getWork")] @@ -196,12 +196,12 @@ build_rpc_trait! { fn new_pending_transaction_filter(&self) -> Result; /// Returns filter changes since last poll. - #[rpc(name = "eth_getFilterChanges")] - fn filter_changes(&self, Index) -> Result; + #[rpc(async, name = "eth_getFilterChanges")] + fn filter_changes(&self, Index) -> BoxFuture; /// Returns all logs matching given filter (in a range 'from' - 'to'). - #[rpc(name = "eth_getFilterLogs")] - fn filter_logs(&self, Index) -> Result, Error>; + #[rpc(async, name = "eth_getFilterLogs")] + fn filter_logs(&self, Index) -> BoxFuture, Error>; /// Uninstalls filter. #[rpc(name = "eth_uninstallFilter")] From 52eae66c72433bbfb359ce19a2935dff7b071ff1 Mon Sep 17 00:00:00 2001 From: keorn Date: Wed, 12 Apr 2017 11:15:13 +0100 Subject: [PATCH 09/29] Add raw hash signing (#5423) * add sign any * Add RPC signMessage call to JS API * Add signMessage to JSON RPC docs * PostSignTransaction -> EthSignMessage * fix doc typo * revert incorect naming --- js/src/api/rpc/parity/parity.js | 5 +++++ js/src/jsonrpc/interfaces/parity.js | 26 ++++++++++++++++++++++ rpc/src/v1/helpers/dispatch.rs | 6 ++--- rpc/src/v1/helpers/requests.rs | 6 ++--- rpc/src/v1/impls/parity_accounts.rs | 15 +++++++++++-- rpc/src/v1/impls/signing.rs | 4 ++-- rpc/src/v1/impls/signing_unsafe.rs | 2 +- rpc/src/v1/tests/mocked/parity_accounts.rs | 17 ++++++++++++++ rpc/src/v1/tests/mocked/signer.rs | 4 ++-- rpc/src/v1/traits/parity_accounts.rs | 6 ++++- rpc/src/v1/types/confirmations.rs | 8 +++---- 11 files changed, 81 insertions(+), 18 deletions(-) diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js index f38e29e7b..16b14eaef 100644 --- a/js/src/api/rpc/parity/parity.js +++ b/js/src/api/rpc/parity/parity.js @@ -522,6 +522,11 @@ export default class Parity { .then(outNumber); } + signMessage (address, password, messageHash) { + return this._transport + .execute('parity_signMessage', inAddress(address), password, inHex(messageHash)); + } + testPassword (account, password) { return this._transport .execute('parity_testPassword', inAddress(account), password); diff --git a/js/src/jsonrpc/interfaces/parity.js b/js/src/jsonrpc/interfaces/parity.js index 3e6fa8475..e7a5f46c9 100644 --- a/js/src/jsonrpc/interfaces/parity.js +++ b/js/src/jsonrpc/interfaces/parity.js @@ -1881,5 +1881,31 @@ export default { desc: 'Decrypted message.', example: withComment('0x68656c6c6f20776f726c64', 'hello world') } + }, + + signMessage: { + desc: 'Sign the hashed message bytes with the given account.', + params: [ + { + type: Address, + desc: 'Account which signs the message.', + example: '0xc171033d5cbff7175f29dfd3a63dda3d6f8f385e' + }, + { + type: String, + desc: 'Passphrase to unlock the account.', + example: 'password1' + }, + { + type: Data, + desc: 'Hashed message.', + example: '0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a' + } + ], + returns: { + type: Data, + desc: 'Message signature.', + example: '0x1d9e33a8cf8bfc089a172bca01da462f9e359c6cb1b0f29398bc884e4d18df4f78588aee4fb5cc067ca62d2abab995e0bba29527be6ac98105b0320020a2efaf00' + } } }; diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index d58a211ed..c6af8d7e7 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -474,7 +474,7 @@ pub fn execute( .map(ConfirmationResponse::SignTransaction) ).boxed() }, - ConfirmationPayload::Signature(address, mut data) => { + ConfirmationPayload::EthSignMessage(address, mut data) => { let mut message_data = format!("\x19Ethereum Signed Message:\n{}", data.len()) .into_bytes(); @@ -574,8 +574,8 @@ pub fn from_rpc(payload: RpcConfirmationPayload, default_account: Address, di RpcConfirmationPayload::Decrypt(RpcDecryptRequest { address, msg }) => { future::ok(ConfirmationPayload::Decrypt(address.into(), msg.into())).boxed() }, - RpcConfirmationPayload::Signature(RpcSignRequest { address, data }) => { - future::ok(ConfirmationPayload::Signature(address.into(), data.into())).boxed() + RpcConfirmationPayload::EthSignMessage(RpcSignRequest { address, data }) => { + future::ok(ConfirmationPayload::EthSignMessage(address.into(), data.into())).boxed() }, } } diff --git a/rpc/src/v1/helpers/requests.rs b/rpc/src/v1/helpers/requests.rs index 4a3a3704d..aa3a4c3d4 100644 --- a/rpc/src/v1/helpers/requests.rs +++ b/rpc/src/v1/helpers/requests.rs @@ -113,8 +113,8 @@ pub enum ConfirmationPayload { SendTransaction(FilledTransactionRequest), /// Sign Transaction SignTransaction(FilledTransactionRequest), - /// Sign request - Signature(Address, Bytes), + /// Sign a message with an Ethereum specific security prefix. + EthSignMessage(Address, Bytes), /// Decrypt request Decrypt(Address, Bytes), } @@ -124,7 +124,7 @@ impl ConfirmationPayload { match *self { ConfirmationPayload::SendTransaction(ref request) => request.from, ConfirmationPayload::SignTransaction(ref request) => request.from, - ConfirmationPayload::Signature(ref address, _) => *address, + ConfirmationPayload::EthSignMessage(ref address, _) => *address, ConfirmationPayload::Decrypt(ref address, _) => *address, } } diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index c22285cc9..cc206696f 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -17,7 +17,7 @@ //! Account management (personal) rpc implementation use std::sync::{Arc, Weak}; use std::collections::BTreeMap; -use util::{Address}; +use util::Address; use ethkey::{Brain, Generator, Secret}; use ethstore::KeyFile; @@ -27,7 +27,7 @@ use jsonrpc_core::Error; use v1::helpers::errors; use v1::helpers::accounts::unwrap_provider; use v1::traits::ParityAccounts; -use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId, Derive, DeriveHierarchical, DeriveHash}; +use v1::types::{H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, DappId, Derive, DeriveHierarchical, DeriveHash}; /// Account management (personal) rpc implementation. pub struct ParityAccountsClient { @@ -334,6 +334,17 @@ impl ParityAccounts for ParityAccountsClient { .map(Into::into) .map_err(|e| errors::account("Could not export account.", e)) } + + fn sign_message(&self, addr: RpcH160, password: String, message: RpcH256) -> Result { + self.account_provider()? + .sign( + addr.into(), + Some(password), + message.into() + ) + .map(Into::into) + .map_err(|e| errors::account("Could not sign message.", e)) + } } fn into_vec(a: Vec) -> Vec where diff --git a/rpc/src/v1/impls/signing.rs b/rpc/src/v1/impls/signing.rs index dfb0c4f80..376418ead 100644 --- a/rpc/src/v1/impls/signing.rs +++ b/rpc/src/v1/impls/signing.rs @@ -140,7 +140,7 @@ impl ParitySigning for SigningQueueClient { fn post_sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture, Error> { let pending = self.pending.clone(); self.dispatch( - RpcConfirmationPayload::Signature((address.clone(), data).into()), + RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()), DefaultAccount::Provided(address.into()), meta.origin ).map(move |result| match result { @@ -216,7 +216,7 @@ impl EthSigning for SigningQueueClient { fn sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture { let res = self.dispatch( - RpcConfirmationPayload::Signature((address.clone(), data).into()), + RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()), address.into(), meta.origin, ); diff --git a/rpc/src/v1/impls/signing_unsafe.rs b/rpc/src/v1/impls/signing_unsafe.rs index 8fbb6595a..6fb483c5e 100644 --- a/rpc/src/v1/impls/signing_unsafe.rs +++ b/rpc/src/v1/impls/signing_unsafe.rs @@ -78,7 +78,7 @@ impl EthSigning for SigningUnsafeClient type Metadata = Metadata; fn sign(&self, _: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture { - self.handle(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into()) + self.handle(RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()), address.into()) .then(|res| match res { Ok(RpcConfirmationResponse::Signature(signature)) => Ok(signature), Err(e) => Err(e), diff --git a/rpc/src/v1/tests/mocked/parity_accounts.rs b/rpc/src/v1/tests/mocked/parity_accounts.rs index 949498c61..b3ea644fa 100644 --- a/rpc/src/v1/tests/mocked/parity_accounts.rs +++ b/rpc/src/v1/tests/mocked/parity_accounts.rs @@ -500,3 +500,20 @@ fn should_export_account() { println!("Response: {:?}", response); assert_eq!(result, Some(response.into())); } + +#[test] +fn should_sign_message() { + let tester = setup(); + let hash = tester.accounts + .insert_account( + "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a".parse().unwrap(), + "password1") + .expect("account should be inserted ok"); + + assert_eq!(hash, "c171033d5cbff7175f29dfd3a63dda3d6f8f385e".parse().unwrap()); + + let request = r#"{"jsonrpc": "2.0", "method": "parity_signMessage", "params": ["0xc171033d5cbff7175f29dfd3a63dda3d6f8f385e", "password1", "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"], "id": 3}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x1d9e33a8cf8bfc089a172bca01da462f9e359c6cb1b0f29398bc884e4d18df4f78588aee4fb5cc067ca62d2abab995e0bba29527be6ac98105b0320020a2efaf00","id":3}"#; + let res = tester.io.handle_request_sync(&request); + assert_eq!(res, Some(response.into())); +} diff --git a/rpc/src/v1/tests/mocked/signer.rs b/rpc/src/v1/tests/mocked/signer.rs index a20e94bcc..973e33528 100644 --- a/rpc/src/v1/tests/mocked/signer.rs +++ b/rpc/src/v1/tests/mocked/signer.rs @@ -90,7 +90,7 @@ fn should_return_list_of_items_to_confirm() { nonce: None, condition: None, }), Origin::Dapps("http://parity.io".into())).unwrap(); - tester.signer.add_request(ConfirmationPayload::Signature(1.into(), vec![5].into()), Origin::Unknown).unwrap(); + tester.signer.add_request(ConfirmationPayload::EthSignMessage(1.into(), vec![5].into()), Origin::Unknown).unwrap(); // when let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#; @@ -163,7 +163,7 @@ fn should_not_remove_transaction_if_password_is_invalid() { fn should_not_remove_sign_if_password_is_invalid() { // given let tester = signer_tester(); - tester.signer.add_request(ConfirmationPayload::Signature(0.into(), vec![5].into()), Origin::Unknown).unwrap(); + tester.signer.add_request(ConfirmationPayload::EthSignMessage(0.into(), vec![5].into()), Origin::Unknown).unwrap(); assert_eq!(tester.signer.requests().len(), 1); // when diff --git a/rpc/src/v1/traits/parity_accounts.rs b/rpc/src/v1/traits/parity_accounts.rs index 46372560c..7d49148b1 100644 --- a/rpc/src/v1/traits/parity_accounts.rs +++ b/rpc/src/v1/traits/parity_accounts.rs @@ -19,7 +19,7 @@ use std::collections::BTreeMap; use jsonrpc_core::Error; use ethstore::KeyFile; -use v1::types::{H160, H256, DappId, DeriveHash, DeriveHierarchical}; +use v1::types::{H160, H256, H520, DappId, DeriveHash, DeriveHierarchical}; build_rpc_trait! { /// Personal Parity rpc interface. @@ -180,5 +180,9 @@ build_rpc_trait! { /// Exports an account with given address if provided password matches. #[rpc(name = "parity_exportAccount")] fn export_account(&self, H160, String) -> Result; + + /// Sign raw hash with the key corresponding to address and password. + #[rpc(name = "parity_signMessage")] + fn sign_message(&self, H160, String, H256) -> Result; } } diff --git a/rpc/src/v1/types/confirmations.rs b/rpc/src/v1/types/confirmations.rs index f749df449..ac1fba4fe 100644 --- a/rpc/src/v1/types/confirmations.rs +++ b/rpc/src/v1/types/confirmations.rs @@ -57,7 +57,7 @@ impl fmt::Display for ConfirmationPayload { match *self { ConfirmationPayload::SendTransaction(ref transaction) => write!(f, "{}", transaction), ConfirmationPayload::SignTransaction(ref transaction) => write!(f, "(Sign only) {}", transaction), - ConfirmationPayload::Signature(ref sign) => write!(f, "{}", sign), + ConfirmationPayload::EthSignMessage(ref sign) => write!(f, "{}", sign), ConfirmationPayload::Decrypt(ref decrypt) => write!(f, "{}", decrypt), } } @@ -169,7 +169,7 @@ pub enum ConfirmationPayload { SignTransaction(TransactionRequest), /// Signature #[serde(rename="sign")] - Signature(SignRequest), + EthSignMessage(SignRequest), /// Decryption #[serde(rename="decrypt")] Decrypt(DecryptRequest), @@ -180,7 +180,7 @@ impl From for ConfirmationPayload { match c { helpers::ConfirmationPayload::SendTransaction(t) => ConfirmationPayload::SendTransaction(t.into()), helpers::ConfirmationPayload::SignTransaction(t) => ConfirmationPayload::SignTransaction(t.into()), - helpers::ConfirmationPayload::Signature(address, data) => ConfirmationPayload::Signature(SignRequest { + helpers::ConfirmationPayload::EthSignMessage(address, data) => ConfirmationPayload::EthSignMessage(SignRequest { address: address.into(), data: data.into(), }), @@ -255,7 +255,7 @@ mod tests { // given let request = helpers::ConfirmationRequest { id: 15.into(), - payload: helpers::ConfirmationPayload::Signature(1.into(), vec![5].into()), + payload: helpers::ConfirmationPayload::EthSignMessage(1.into(), vec![5].into()), origin: Origin::Rpc("test service".into()), }; From a0d83537e54d77d9565c242695a1ac53ab013f26 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Wed, 12 Apr 2017 10:48:49 +0000 Subject: [PATCH 10/29] [ci skip] js-precompiled 20170412-104510 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f710cc18..c7e412349 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1761,7 +1761,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#f4fa3048dcb0e202c53a61b9b9e7dd446fa1c088" +source = "git+https://github.com/paritytech/js-precompiled.git#fb24b1a459fc7f5b3de5fe21060bc17e1e161e5e" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index e4bf27430..f20ea0574 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.50", + "version": "1.7.51", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 1b36a381e80ce20f8bdd3dfc849434c7ed1a4496 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 12 Apr 2017 13:20:22 +0200 Subject: [PATCH 11/29] Fix buffer length for QR code gen. (#5447) --- js/src/ui/QrCode/qrSize.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/ui/QrCode/qrSize.js b/js/src/ui/QrCode/qrSize.js index 2671bb532..8440458ac 100644 --- a/js/src/ui/QrCode/qrSize.js +++ b/js/src/ui/QrCode/qrSize.js @@ -69,7 +69,9 @@ const QR_SIZES = [ export function calculateType (lengthBytes, errorLevel = 'M') { let type = 5; - while (type < 40 && lengthBytes > QR_SIZES[errorLevel][type - 1]) { + // subtract 3 from the capacities, since we need 2 bits for the mode and a + // bunch more for the length. + while (type < 40 && lengthBytes > QR_SIZES[errorLevel][type - 1] - 3) { type++; } From 15ae24b5412cb704d5f24d096cc33325526501f1 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Wed, 12 Apr 2017 13:33:49 +0200 Subject: [PATCH 12/29] New state tests (#5418) * General state tests * Allow dir name for a test --- ethcore/res/ethereum/eip150_test.json | 3 +- ethcore/res/ethereum/eip161_test.json | 3 +- ethcore/res/ethereum/tests | 2 +- ethcore/src/json_tests/chain.rs | 2 +- ethcore/src/json_tests/eip150_state.rs | 43 -- ethcore/src/json_tests/eip161_state.rs | 51 -- ethcore/src/json_tests/homestead_chain.rs | 1 - ethcore/src/json_tests/homestead_state.rs | 39 -- ethcore/src/json_tests/mod.rs | 3 - ethcore/src/json_tests/state.rs | 790 ++-------------------- ethcore/src/json_tests/test_common.rs | 52 +- ethcore/src/tests/helpers.rs | 13 +- json/src/maybe.rs | 2 +- json/src/state/test.rs | 192 +++++- 14 files changed, 328 insertions(+), 868 deletions(-) delete mode 100644 ethcore/src/json_tests/eip150_state.rs delete mode 100644 ethcore/src/json_tests/eip161_state.rs delete mode 100644 ethcore/src/json_tests/homestead_state.rs diff --git a/ethcore/res/ethereum/eip150_test.json b/ethcore/res/ethereum/eip150_test.json index f43abea4b..8331c8fc2 100644 --- a/ethcore/res/ethereum/eip150_test.json +++ b/ethcore/res/ethereum/eip150_test.json @@ -14,7 +14,8 @@ "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "eip161dTransition": "0x7fffffffffffffff", + "maxCodeSize": 24576 } } }, diff --git a/ethcore/res/ethereum/eip161_test.json b/ethcore/res/ethereum/eip161_test.json index b51d052c9..00885bae1 100644 --- a/ethcore/res/ethereum/eip161_test.json +++ b/ethcore/res/ethereum/eip161_test.json @@ -14,7 +14,8 @@ "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x0", "eip161abcTransition": "0x0", - "eip161dTransition": "0x0" + "eip161dTransition": "0x0", + "maxCodeSize": 24576 } } }, diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index 9028c4801..d52059307 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 9028c4801fd39fbb71a9796979182549a24e81c8 +Subproject commit d520593078fa0849dcd1f907e44ed0a616892e33 diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 987280bc1..45a4f1d52 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -48,7 +48,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Homestead => ethereum::new_homestead_test(), ChainEra::Eip150 => ethereum::new_eip150_test(), - ChainEra::Eip161 => ethereum::new_eip161_test(), + ChainEra::_Eip161 => ethereum::new_eip161_test(), ChainEra::TransitionTest => ethereum::new_transition_test(), }; spec.set_genesis_state(state); diff --git a/ethcore/src/json_tests/eip150_state.rs b/ethcore/src/json_tests/eip150_state.rs deleted file mode 100644 index fffb3f57a..000000000 --- a/ethcore/src/json_tests/eip150_state.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use super::test_common::*; -use tests::helpers::*; -use super::state::json_chain_test; - -fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data, ChainEra::Eip150) -} - -declare_test!{StateTests_EIP150_stEIPSpecificTest, "StateTests/EIP150/stEIPSpecificTest"} -declare_test!{StateTests_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP150/stEIPsingleCodeGasPrices"} -declare_test!{StateTests_EIP150_stMemExpandingEIPCalls, "StateTests/EIP150/stMemExpandingEIPCalls"} - -declare_test!{StateTests_EIP150_stCallCodes, "StateTests/EIP150/Homestead/stCallCodes"} -declare_test!{StateTests_EIP150_stCallCreateCallCodeTest, "StateTests/EIP150/Homestead/stCallCreateCallCodeTest"} -declare_test!{StateTests_EIP150_stDelegatecallTest, "StateTests/EIP150/Homestead/stDelegatecallTest"} -declare_test!{StateTests_EIP150_stInitCodeTest, "StateTests/EIP150/Homestead/stInitCodeTest"} -declare_test!{StateTests_EIP150_stLogTests, "StateTests/EIP150/Homestead/stLogTests"} -declare_test!{heavy => StateTests_EIP150_stMemoryStressTest, "StateTests/EIP150/Homestead/stMemoryStressTest"} -declare_test!{heavy => StateTests_EIP150_stMemoryTest, "StateTests/EIP150/Homestead/stMemoryTest"} -declare_test!{StateTests_EIP150_stPreCompiledContracts, "StateTests/EIP150/Homestead/stPreCompiledContracts"} -declare_test!{heavy => StateTests_EIP150_stQuadraticComplexityTest, "StateTests/EIP150/Homestead/stQuadraticComplexityTest"} -declare_test!{StateTests_EIP150_stRecursiveCreate, "StateTests/EIP150/Homestead/stRecursiveCreate"} -declare_test!{StateTests_EIP150_stRefundTest, "StateTests/EIP150/Homestead/stRefundTest"} -declare_test!{StateTests_EIP150_stSpecialTest, "StateTests/EIP150/Homestead/stSpecialTest"} -declare_test!{StateTests_EIP150_stSystemOperationsTest, "StateTests/EIP150/Homestead/stSystemOperationsTest"} -declare_test!{StateTests_EIP150_stTransactionTest, "StateTests/EIP150/Homestead/stTransactionTest"} -declare_test!{StateTests_EIP150_stWalletTest, "StateTests/EIP150/Homestead/stWalletTest"} diff --git a/ethcore/src/json_tests/eip161_state.rs b/ethcore/src/json_tests/eip161_state.rs deleted file mode 100644 index 44ad6a30a..000000000 --- a/ethcore/src/json_tests/eip161_state.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use super::test_common::*; -use tests::helpers::*; -use super::state::json_chain_test; - -fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data, ChainEra::Eip161) -} - -declare_test!{StateTests_EIP158_stEIP158SpecificTest, "StateTests/EIP158/stEIP158SpecificTest"} -declare_test!{StateTests_EIP158_stNonZeroCallsTest, "StateTests/EIP158/stNonZeroCallsTest"} -declare_test!{StateTests_EIP158_stZeroCallsTest, "StateTests/EIP158/stZeroCallsTest"} - -declare_test!{StateTests_EIP158_EIP150_stMemExpandingEIPCalls, "StateTests/EIP158/EIP150/stMemExpandingEIPCalls"} -declare_test!{StateTests_EIP158_EIP150_stEIPSpecificTest, "StateTests/EIP158/EIP150/stEIPSpecificTest"} -declare_test!{StateTests_EIP158_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP158/EIP150/stEIPsingleCodeGasPrices"} -declare_test!{StateTests_EIP158_EIP150_stChangedTests, "StateTests/EIP158/EIP150/stChangedTests"} - -declare_test!{StateTests_EIP158_Homestead_stBoundsTest, "StateTests/EIP158/Homestead/stBoundsTest"} -declare_test!{StateTests_EIP158_Homestead_stCallCodes, "StateTests/EIP158/Homestead/stCallCodes"} -declare_test!{StateTests_EIP158_Homestead_stCallCreateCallCodeTest, "StateTests/EIP158/Homestead/stCallCreateCallCodeTest"} -declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodes, "StateTests/EIP158/Homestead/stCallDelegateCodes"} -declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodesCallCode, "StateTests/EIP158/Homestead/stCallDelegateCodesCallCode"} -declare_test!{StateTests_EIP158_Homestead_stDelegatecallTest, "StateTests/EIP158/Homestead/stDelegatecallTest"} -declare_test!{StateTests_EIP158_Homestead_stHomeSteadSpecific, "StateTests/EIP158/Homestead/stHomeSteadSpecific"} -declare_test!{StateTests_EIP158_Homestead_stInitCodeTest, "StateTests/EIP158/Homestead/stInitCodeTest"} -declare_test!{StateTests_EIP158_Homestead_stLogTests, "StateTests/EIP158/Homestead/stLogTests"} -declare_test!{heavy => StateTests_EIP158_Homestead_stMemoryTest, "StateTests/EIP158/Homestead/stMemoryTest"} -declare_test!{StateTests_EIP158_Homestead_stPreCompiledContracts, "StateTests/EIP158/Homestead/stPreCompiledContracts"} -declare_test!{heavy => StateTests_EIP158_Homestead_stQuadraticComplexityTest, "StateTests/EIP158/Homestead/stQuadraticComplexityTest"} -declare_test!{StateTests_EIP158_Homestead_stRecursiveCreate, "StateTests/EIP158/Homestead/stRecursiveCreate"} -declare_test!{StateTests_EIP158_Homestead_stRefundTest, "StateTests/EIP158/Homestead/stRefundTest"} -declare_test!{StateTests_EIP158_Homestead_stSpecialTest, "StateTests/EIP158/Homestead/stSpecialTest"} -declare_test!{StateTests_EIP158_Homestead_stSystemOperationsTest, "StateTests/EIP158/Homestead/stSystemOperationsTest"} -declare_test!{StateTests_EIP158_Homestead_stTransactionTest, "StateTests/EIP158/Homestead/stTransactionTest"} -declare_test!{StateTests_EIP158_Homestead_stWalletTest, "StateTests/EIP158/Homestead/stWalletTest"} \ No newline at end of file diff --git a/ethcore/src/json_tests/homestead_chain.rs b/ethcore/src/json_tests/homestead_chain.rs index aab07674b..5f0fe5769 100644 --- a/ethcore/src/json_tests/homestead_chain.rs +++ b/ethcore/src/json_tests/homestead_chain.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use super::test_common::*; use super::chain::json_chain_test; use tests::helpers::*; diff --git a/ethcore/src/json_tests/homestead_state.rs b/ethcore/src/json_tests/homestead_state.rs deleted file mode 100644 index c8585ff15..000000000 --- a/ethcore/src/json_tests/homestead_state.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use super::test_common::*; -use tests::helpers::*; -use super::state::json_chain_test; - -fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data, ChainEra::Homestead) -} - -declare_test!{StateTests_Homestead_stCallCodes, "StateTests/Homestead/stCallCodes"} -declare_test!{StateTests_Homestead_stCallCreateCallCodeTest, "StateTests/Homestead/stCallCreateCallCodeTest"} -declare_test!{StateTests_Homestead_stDelegatecallTest, "StateTests/Homestead/stDelegatecallTest"} -declare_test!{StateTests_Homestead_stInitCodeTest, "StateTests/Homestead/stInitCodeTest"} -declare_test!{StateTests_Homestead_stLogTests, "StateTests/Homestead/stLogTests"} -declare_test!{heavy => StateTests_Homestead_stMemoryStressTest, "StateTests/Homestead/stMemoryStressTest"} -declare_test!{heavy => StateTests_Homestead_stMemoryTest, "StateTests/Homestead/stMemoryTest"} -declare_test!{StateTests_Homestead_stPreCompiledContracts, "StateTests/Homestead/stPreCompiledContracts"} -declare_test!{heavy => StateTests_Homestead_stQuadraticComplexityTest, "StateTests/Homestead/stQuadraticComplexityTest"} -declare_test!{StateTests_Homestead_stRecursiveCreate, "StateTests/Homestead/stRecursiveCreate"} -declare_test!{StateTests_Homestead_stRefundTest, "StateTests/Homestead/stRefundTest"} -declare_test!{StateTests_Homestead_stSpecialTest, "StateTests/Homestead/stSpecialTest"} -declare_test!{StateTests_Homestead_stSystemOperationsTest, "StateTests/Homestead/stSystemOperationsTest"} -declare_test!{StateTests_Homestead_stTransactionTest, "StateTests/Homestead/stTransactionTest"} -declare_test!{StateTests_Homestead_stWalletTest, "StateTests/Homestead/stWalletTest"} diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs index 22f0dca03..406782072 100644 --- a/ethcore/src/json_tests/mod.rs +++ b/ethcore/src/json_tests/mod.rs @@ -21,8 +21,5 @@ mod transaction; mod executive; mod state; mod chain; -mod homestead_state; mod homestead_chain; -mod eip150_state; -mod eip161_state; mod trie; diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index 6388daf94..e4b9390db 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -16,749 +16,109 @@ use super::test_common::*; use tests::helpers::*; -use pod_state::{self, PodState}; -use log_entry::LogEntry; +use pod_state::PodState; use ethereum; +use spec::Spec; use ethjson; +use ethjson::state::test::ForkSpec; -pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { +lazy_static! { + pub static ref FRONTIER: Spec = ethereum::new_frontier_test(); + pub static ref HOMESTEAD: Spec = ethereum::new_homestead_test(); + pub static ref EIP150: Spec = ethereum::new_eip150_test(); + pub static ref EIP161: Spec = ethereum::new_eip161_test(); +} + +pub fn json_chain_test(json_data: &[u8]) -> Vec { ::ethcore_logger::init_log(); - let tests = ethjson::state::Test::load(json_data).unwrap(); + let tests = ethjson::state::test::Test::load(json_data).unwrap(); let mut failed = Vec::new(); - let engine = match era { - ChainEra::Frontier => ethereum::new_mainnet_like().engine, - ChainEra::Homestead => ethereum::new_homestead_test().engine, - ChainEra::Eip150 => ethereum::new_eip150_test().engine, - ChainEra::Eip161 => ethereum::new_eip161_test().engine, - ChainEra::TransitionTest => ethereum::new_transition_test().engine, - }; for (name, test) in tests.into_iter() { - let mut fail = false; { - let mut fail_unless = |cond: bool| if !cond && !fail { - failed.push(name.clone()); - flushln!("FAIL"); - fail = true; - true - } else {false}; - - flush!(" - {}...", name); - - let transaction = test.transaction.into(); - let post_state_root = test.post_state_root.into(); + let multitransaction = test.transaction; let env = test.env.into(); let pre: PodState = test.pre_state.into(); - let post: PodState = test.post_state.into(); - let logs: Vec = test.logs.into_iter().map(Into::into).collect(); - let calc_post = sec_trie_root(post.get().iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect()); + for (spec, states) in test.post_states { + let total = states.len(); + let engine = match spec { + ForkSpec::Frontier => &FRONTIER.engine, + ForkSpec::Homestead => &HOMESTEAD.engine, + ForkSpec::EIP150 => &EIP150.engine, + ForkSpec::EIP158 => &EIP161.engine, + ForkSpec::Metropolis => continue, + }; - if fail_unless(post_state_root == calc_post) { - println!("!!! {}: Trie root mismatch (got: {}, expect: {}):", name, calc_post, post_state_root); - println!("!!! Post:\n{}", post); - } else { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - state.populate_from(pre); - state.commit() - .expect(&format!("State test {} failed due to internal error.", name)); - let res = state.apply(&env, &*engine, &transaction, false); + for (i, state) in states.into_iter().enumerate() { + let info = format!(" - {} | {:?} ({}/{}) ...", name, spec, i + 1, total); - if fail_unless(state.root() == &post_state_root) { - println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root); - let our_post = state.to_pod(); - println!("Got:\n{}", our_post); - println!("Expect:\n{}", post); - println!("Diff ---expect -> +++got:\n{}", pod_state::diff_pod(&post, &our_post)); - } + let post_root: H256 = state.hash.into(); + let transaction = multitransaction.select(&state.indexes).into(); - if let Ok(r) = res { - if fail_unless(logs == r.receipt.logs) { - println!("!!! {}: Logs mismatch:", name); - println!("Got:\n{:?}", r.receipt.logs); - println!("Expect:\n{:?}", logs); + let mut state = get_temp_mem_state(); + state.populate_from(pre.clone()); + state.commit().expect(&format!("State test {} failed due to internal error.", name)); + let _res = state.apply(&env, &**engine, &transaction, false); + if state.root() != &post_root { + println!("{} !!! State mismatch (got: {}, expect: {}", info, state.root(), post_root); + flushln!("{} fail", info); + failed.push(name.clone()); + } else { + flushln!("{} ok", info); } } } } - if !fail { - flushln!("ok"); - } } println!("!!! {:?} tests from failed.", failed.len()); failed } -mod frontier_tests { +mod state_tests { use super::json_chain_test; - use tests::helpers::ChainEra; fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data, ChainEra::Frontier) + json_chain_test(json_data) } - declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"} - declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"} - declare_test!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} - declare_test!{StateTests_stExample, "StateTests/stExample"} - declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"} - declare_test!{StateTests_stLogTests, "StateTests/stLogTests"} - declare_test!{heavy => StateTests_stMemoryStressTest, "StateTests/stMemoryStressTest"} - declare_test!{heavy => StateTests_stMemoryTest, "StateTests/stMemoryTest"} - declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"} - declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} - declare_test!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} - declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"} - declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} - declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} - declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} - declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} - declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} - declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} - - declare_test!{StateTests_RandomTests_st201503121803PYTHON, "StateTests/RandomTests/st201503121803PYTHON"} - declare_test!{StateTests_RandomTests_st201503121806PYTHON, "StateTests/RandomTests/st201503121806PYTHON"} - declare_test!{StateTests_RandomTests_st201503121848GO, "StateTests/RandomTests/st201503121848GO"} - declare_test!{StateTests_RandomTests_st201503121849GO, "StateTests/RandomTests/st201503121849GO"} - declare_test!{StateTests_RandomTests_st201503121850GO, "StateTests/RandomTests/st201503121850GO"} - declare_test!{StateTests_RandomTests_st201503121851GO, "StateTests/RandomTests/st201503121851GO"} - declare_test!{StateTests_RandomTests_st201503121953GO, "StateTests/RandomTests/st201503121953GO"} - declare_test!{StateTests_RandomTests_st201503122023GO, "StateTests/RandomTests/st201503122023GO"} - declare_test!{StateTests_RandomTests_st201503122023PYTHON, "StateTests/RandomTests/st201503122023PYTHON"} - declare_test!{StateTests_RandomTests_st201503122027GO, "StateTests/RandomTests/st201503122027GO"} - declare_test!{StateTests_RandomTests_st201503122054GO, "StateTests/RandomTests/st201503122054GO"} - declare_test!{StateTests_RandomTests_st201503122055GO, "StateTests/RandomTests/st201503122055GO"} - declare_test!{StateTests_RandomTests_st201503122115CPPJIT, "StateTests/RandomTests/st201503122115CPPJIT"} - declare_test!{StateTests_RandomTests_st201503122115GO, "StateTests/RandomTests/st201503122115GO"} - declare_test!{StateTests_RandomTests_st201503122123GO, "StateTests/RandomTests/st201503122123GO"} - declare_test!{StateTests_RandomTests_st201503122124GO, "StateTests/RandomTests/st201503122124GO"} - declare_test!{StateTests_RandomTests_st201503122128PYTHON, "StateTests/RandomTests/st201503122128PYTHON"} - declare_test!{StateTests_RandomTests_st201503122140GO, "StateTests/RandomTests/st201503122140GO"} - declare_test!{StateTests_RandomTests_st201503122159GO, "StateTests/RandomTests/st201503122159GO"} - declare_test!{StateTests_RandomTests_st201503122204GO, "StateTests/RandomTests/st201503122204GO"} - declare_test!{StateTests_RandomTests_st201503122212GO, "StateTests/RandomTests/st201503122212GO"} - declare_test!{StateTests_RandomTests_st201503122231GO, "StateTests/RandomTests/st201503122231GO"} - declare_test!{StateTests_RandomTests_st201503122238GO, "StateTests/RandomTests/st201503122238GO"} - declare_test!{StateTests_RandomTests_st201503122252GO, "StateTests/RandomTests/st201503122252GO"} - declare_test!{StateTests_RandomTests_st201503122316GO, "StateTests/RandomTests/st201503122316GO"} - declare_test!{StateTests_RandomTests_st201503122324GO, "StateTests/RandomTests/st201503122324GO"} - declare_test!{StateTests_RandomTests_st201503122358GO, "StateTests/RandomTests/st201503122358GO"} - declare_test!{StateTests_RandomTests_st201503130002GO, "StateTests/RandomTests/st201503130002GO"} - declare_test!{StateTests_RandomTests_st201503130005GO, "StateTests/RandomTests/st201503130005GO"} - declare_test!{StateTests_RandomTests_st201503130007GO, "StateTests/RandomTests/st201503130007GO"} - declare_test!{StateTests_RandomTests_st201503130010GO, "StateTests/RandomTests/st201503130010GO"} - declare_test!{StateTests_RandomTests_st201503130023PYTHON, "StateTests/RandomTests/st201503130023PYTHON"} - declare_test!{StateTests_RandomTests_st201503130059GO, "StateTests/RandomTests/st201503130059GO"} - declare_test!{StateTests_RandomTests_st201503130101GO, "StateTests/RandomTests/st201503130101GO"} - declare_test!{StateTests_RandomTests_st201503130109GO, "StateTests/RandomTests/st201503130109GO"} - declare_test!{StateTests_RandomTests_st201503130117GO, "StateTests/RandomTests/st201503130117GO"} - declare_test!{StateTests_RandomTests_st201503130122GO, "StateTests/RandomTests/st201503130122GO"} - declare_test!{StateTests_RandomTests_st201503130156GO, "StateTests/RandomTests/st201503130156GO"} - declare_test!{StateTests_RandomTests_st201503130156PYTHON, "StateTests/RandomTests/st201503130156PYTHON"} - declare_test!{StateTests_RandomTests_st201503130207GO, "StateTests/RandomTests/st201503130207GO"} - declare_test!{StateTests_RandomTests_st201503130219CPPJIT, "StateTests/RandomTests/st201503130219CPPJIT"} - declare_test!{StateTests_RandomTests_st201503130219GO, "StateTests/RandomTests/st201503130219GO"} - declare_test!{StateTests_RandomTests_st201503130243GO, "StateTests/RandomTests/st201503130243GO"} - declare_test!{StateTests_RandomTests_st201503130246GO, "StateTests/RandomTests/st201503130246GO"} - declare_test!{StateTests_RandomTests_st201503130321GO, "StateTests/RandomTests/st201503130321GO"} - declare_test!{StateTests_RandomTests_st201503130322GO, "StateTests/RandomTests/st201503130322GO"} - declare_test!{StateTests_RandomTests_st201503130332GO, "StateTests/RandomTests/st201503130332GO"} - declare_test!{StateTests_RandomTests_st201503130359GO, "StateTests/RandomTests/st201503130359GO"} - declare_test!{StateTests_RandomTests_st201503130405GO, "StateTests/RandomTests/st201503130405GO"} - declare_test!{StateTests_RandomTests_st201503130408GO, "StateTests/RandomTests/st201503130408GO"} - declare_test!{StateTests_RandomTests_st201503130411GO, "StateTests/RandomTests/st201503130411GO"} - declare_test!{StateTests_RandomTests_st201503130431GO, "StateTests/RandomTests/st201503130431GO"} - declare_test!{StateTests_RandomTests_st201503130437GO, "StateTests/RandomTests/st201503130437GO"} - declare_test!{StateTests_RandomTests_st201503130450GO, "StateTests/RandomTests/st201503130450GO"} - declare_test!{StateTests_RandomTests_st201503130512CPPJIT, "StateTests/RandomTests/st201503130512CPPJIT"} - declare_test!{StateTests_RandomTests_st201503130512GO, "StateTests/RandomTests/st201503130512GO"} - declare_test!{StateTests_RandomTests_st201503130615GO, "StateTests/RandomTests/st201503130615GO"} - declare_test!{StateTests_RandomTests_st201503130705GO, "StateTests/RandomTests/st201503130705GO"} - declare_test!{StateTests_RandomTests_st201503130733CPPJIT, "StateTests/RandomTests/st201503130733CPPJIT"} - declare_test!{StateTests_RandomTests_st201503130733GO, "StateTests/RandomTests/st201503130733GO"} - declare_test!{StateTests_RandomTests_st201503130747GO, "StateTests/RandomTests/st201503130747GO"} - declare_test!{StateTests_RandomTests_st201503130751GO, "StateTests/RandomTests/st201503130751GO"} - declare_test!{StateTests_RandomTests_st201503130752PYTHON, "StateTests/RandomTests/st201503130752PYTHON"} - declare_test!{StateTests_RandomTests_st201503130757PYTHON, "StateTests/RandomTests/st201503130757PYTHON"} - declare_test!{StateTests_RandomTests_st201503131658GO, "StateTests/RandomTests/st201503131658GO"} - declare_test!{StateTests_RandomTests_st201503131739GO, "StateTests/RandomTests/st201503131739GO"} - declare_test!{StateTests_RandomTests_st201503131755CPPJIT, "StateTests/RandomTests/st201503131755CPPJIT"} - declare_test!{StateTests_RandomTests_st201503131755GO, "StateTests/RandomTests/st201503131755GO"} - declare_test!{StateTests_RandomTests_st201503132001CPPJIT, "StateTests/RandomTests/st201503132001CPPJIT"} - declare_test!{StateTests_RandomTests_st201503132127PYTHON, "StateTests/RandomTests/st201503132127PYTHON"} - declare_test!{StateTests_RandomTests_st201503132201CPPJIT, "StateTests/RandomTests/st201503132201CPPJIT"} - declare_test!{StateTests_RandomTests_st201503132201GO, "StateTests/RandomTests/st201503132201GO"} - declare_test!{StateTests_RandomTests_st201503132202PYTHON, "StateTests/RandomTests/st201503132202PYTHON"} - declare_test!{StateTests_RandomTests_st201503140002PYTHON, "StateTests/RandomTests/st201503140002PYTHON"} - declare_test!{StateTests_RandomTests_st201503140240PYTHON, "StateTests/RandomTests/st201503140240PYTHON"} - declare_test!{StateTests_RandomTests_st201503140522PYTHON, "StateTests/RandomTests/st201503140522PYTHON"} - declare_test!{StateTests_RandomTests_st201503140756PYTHON, "StateTests/RandomTests/st201503140756PYTHON"} - declare_test!{StateTests_RandomTests_st201503141144PYTHON, "StateTests/RandomTests/st201503141144PYTHON"} - declare_test!{StateTests_RandomTests_st201503141510PYTHON, "StateTests/RandomTests/st201503141510PYTHON"} - declare_test!{StateTests_RandomTests_st201503150427PYTHON, "StateTests/RandomTests/st201503150427PYTHON"} - declare_test!{StateTests_RandomTests_st201503150716PYTHON, "StateTests/RandomTests/st201503150716PYTHON"} - declare_test!{StateTests_RandomTests_st201503151450PYTHON, "StateTests/RandomTests/st201503151450PYTHON"} - declare_test!{StateTests_RandomTests_st201503151516PYTHON, "StateTests/RandomTests/st201503151516PYTHON"} - declare_test!{StateTests_RandomTests_st201503151753PYTHON, "StateTests/RandomTests/st201503151753PYTHON"} - declare_test!{StateTests_RandomTests_st201503152057PYTHON, "StateTests/RandomTests/st201503152057PYTHON"} - declare_test!{StateTests_RandomTests_st201503152241PYTHON, "StateTests/RandomTests/st201503152241PYTHON"} - declare_test!{StateTests_RandomTests_st201503160014PYTHON, "StateTests/RandomTests/st201503160014PYTHON"} - declare_test!{StateTests_RandomTests_st201503160733PYTHON, "StateTests/RandomTests/st201503160733PYTHON"} - declare_test!{StateTests_RandomTests_st201503170051PYTHON, "StateTests/RandomTests/st201503170051PYTHON"} - declare_test!{StateTests_RandomTests_st201503170433PYTHON, "StateTests/RandomTests/st201503170433PYTHON"} - declare_test!{StateTests_RandomTests_st201503170523PYTHON, "StateTests/RandomTests/st201503170523PYTHON"} - declare_test!{StateTests_RandomTests_st201503171108PYTHON, "StateTests/RandomTests/st201503171108PYTHON"} - declare_test!{StateTests_RandomTests_st201503181223GO, "StateTests/RandomTests/st201503181223GO"} - declare_test!{StateTests_RandomTests_st201503181225GO, "StateTests/RandomTests/st201503181225GO"} - declare_test!{StateTests_RandomTests_st201503181226CPPJIT, "StateTests/RandomTests/st201503181226CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181227CPPJIT, "StateTests/RandomTests/st201503181227CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181227GO, "StateTests/RandomTests/st201503181227GO"} - declare_test!{StateTests_RandomTests_st201503181229GO, "StateTests/RandomTests/st201503181229GO"} - declare_test!{StateTests_RandomTests_st201503181230CPPJIT, "StateTests/RandomTests/st201503181230CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181230GO, "StateTests/RandomTests/st201503181230GO"} - declare_test!{StateTests_RandomTests_st201503181231GO, "StateTests/RandomTests/st201503181231GO"} - declare_test!{StateTests_RandomTests_st201503181232CPPJIT, "StateTests/RandomTests/st201503181232CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181232GO, "StateTests/RandomTests/st201503181232GO"} - declare_test!{StateTests_RandomTests_st201503181233GO, "StateTests/RandomTests/st201503181233GO"} - declare_test!{StateTests_RandomTests_st201503181234CPPJIT, "StateTests/RandomTests/st201503181234CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181234GO, "StateTests/RandomTests/st201503181234GO"} - declare_test!{StateTests_RandomTests_st201503181235CPPJIT, "StateTests/RandomTests/st201503181235CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181235GO, "StateTests/RandomTests/st201503181235GO"} - declare_test!{StateTests_RandomTests_st201503181236GO, "StateTests/RandomTests/st201503181236GO"} - declare_test!{StateTests_RandomTests_st201503181237GO, "StateTests/RandomTests/st201503181237GO"} - declare_test!{StateTests_RandomTests_st201503181239GO, "StateTests/RandomTests/st201503181239GO"} - declare_test!{StateTests_RandomTests_st201503181241CPPJIT, "StateTests/RandomTests/st201503181241CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181241GO, "StateTests/RandomTests/st201503181241GO"} - declare_test!{StateTests_RandomTests_st201503181243GO, "StateTests/RandomTests/st201503181243GO"} - declare_test!{StateTests_RandomTests_st201503181244GO, "StateTests/RandomTests/st201503181244GO"} - declare_test!{StateTests_RandomTests_st201503181245CPPJIT, "StateTests/RandomTests/st201503181245CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181245GO, "StateTests/RandomTests/st201503181245GO"} - declare_test!{StateTests_RandomTests_st201503181246CPPJIT, "StateTests/RandomTests/st201503181246CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181246GO, "StateTests/RandomTests/st201503181246GO"} - declare_test!{StateTests_RandomTests_st201503181247GO, "StateTests/RandomTests/st201503181247GO"} - declare_test!{StateTests_RandomTests_st201503181248GO, "StateTests/RandomTests/st201503181248GO"} - declare_test!{StateTests_RandomTests_st201503181249GO, "StateTests/RandomTests/st201503181249GO"} - declare_test!{StateTests_RandomTests_st201503181250CPPJIT, "StateTests/RandomTests/st201503181250CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181250GO, "StateTests/RandomTests/st201503181250GO"} - declare_test!{StateTests_RandomTests_st201503181251GO, "StateTests/RandomTests/st201503181251GO"} - declare_test!{StateTests_RandomTests_st201503181252CPPJIT, "StateTests/RandomTests/st201503181252CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181253GO, "StateTests/RandomTests/st201503181253GO"} - declare_test!{StateTests_RandomTests_st201503181255CPPJIT, "StateTests/RandomTests/st201503181255CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181255GO, "StateTests/RandomTests/st201503181255GO"} - declare_test!{StateTests_RandomTests_st201503181257GO, "StateTests/RandomTests/st201503181257GO"} - declare_test!{StateTests_RandomTests_st201503181258CPPJIT, "StateTests/RandomTests/st201503181258CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181258GO, "StateTests/RandomTests/st201503181258GO"} - declare_test!{StateTests_RandomTests_st201503181301CPPJIT, "StateTests/RandomTests/st201503181301CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181301GO, "StateTests/RandomTests/st201503181301GO"} - declare_test!{StateTests_RandomTests_st201503181303GO, "StateTests/RandomTests/st201503181303GO"} - declare_test!{StateTests_RandomTests_st201503181304GO, "StateTests/RandomTests/st201503181304GO"} - declare_test!{StateTests_RandomTests_st201503181305GO, "StateTests/RandomTests/st201503181305GO"} - declare_test!{StateTests_RandomTests_st201503181306GO, "StateTests/RandomTests/st201503181306GO"} - declare_test!{StateTests_RandomTests_st201503181307CPPJIT, "StateTests/RandomTests/st201503181307CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181307GO, "StateTests/RandomTests/st201503181307GO"} - declare_test!{StateTests_RandomTests_st201503181308GO, "StateTests/RandomTests/st201503181308GO"} - declare_test!{StateTests_RandomTests_st201503181309GO, "StateTests/RandomTests/st201503181309GO"} - declare_test!{StateTests_RandomTests_st201503181310GO, "StateTests/RandomTests/st201503181310GO"} - declare_test!{StateTests_RandomTests_st201503181311GO, "StateTests/RandomTests/st201503181311GO"} - declare_test!{StateTests_RandomTests_st201503181313GO, "StateTests/RandomTests/st201503181313GO"} - declare_test!{StateTests_RandomTests_st201503181314GO, "StateTests/RandomTests/st201503181314GO"} - declare_test!{StateTests_RandomTests_st201503181315CPPJIT, "StateTests/RandomTests/st201503181315CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181315GO, "StateTests/RandomTests/st201503181315GO"} - declare_test!{StateTests_RandomTests_st201503181316CPPJIT, "StateTests/RandomTests/st201503181316CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181316PYTHON, "StateTests/RandomTests/st201503181316PYTHON"} - declare_test!{StateTests_RandomTests_st201503181317GO, "StateTests/RandomTests/st201503181317GO"} - declare_test!{StateTests_RandomTests_st201503181318CPPJIT, "StateTests/RandomTests/st201503181318CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181318GO, "StateTests/RandomTests/st201503181318GO"} - declare_test!{StateTests_RandomTests_st201503181319GO, "StateTests/RandomTests/st201503181319GO"} - declare_test!{StateTests_RandomTests_st201503181319PYTHON, "StateTests/RandomTests/st201503181319PYTHON"} - declare_test!{StateTests_RandomTests_st201503181322GO, "StateTests/RandomTests/st201503181322GO"} - declare_test!{StateTests_RandomTests_st201503181323CPPJIT, "StateTests/RandomTests/st201503181323CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181323GO, "StateTests/RandomTests/st201503181323GO"} - declare_test!{StateTests_RandomTests_st201503181324GO, "StateTests/RandomTests/st201503181324GO"} - declare_test!{StateTests_RandomTests_st201503181325GO, "StateTests/RandomTests/st201503181325GO"} - declare_test!{StateTests_RandomTests_st201503181326CPPJIT, "StateTests/RandomTests/st201503181326CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181326GO, "StateTests/RandomTests/st201503181326GO"} - declare_test!{StateTests_RandomTests_st201503181327GO, "StateTests/RandomTests/st201503181327GO"} - declare_test!{StateTests_RandomTests_st201503181329CPPJIT, "StateTests/RandomTests/st201503181329CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181329GO, "StateTests/RandomTests/st201503181329GO"} - declare_test!{StateTests_RandomTests_st201503181330GO, "StateTests/RandomTests/st201503181330GO"} - declare_test!{StateTests_RandomTests_st201503181332GO, "StateTests/RandomTests/st201503181332GO"} - declare_test!{StateTests_RandomTests_st201503181333GO, "StateTests/RandomTests/st201503181333GO"} - declare_test!{StateTests_RandomTests_st201503181334GO, "StateTests/RandomTests/st201503181334GO"} - declare_test!{StateTests_RandomTests_st201503181336CPPJIT, "StateTests/RandomTests/st201503181336CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181337GO, "StateTests/RandomTests/st201503181337GO"} - declare_test!{StateTests_RandomTests_st201503181338GO, "StateTests/RandomTests/st201503181338GO"} - declare_test!{StateTests_RandomTests_st201503181339CPPJIT, "StateTests/RandomTests/st201503181339CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181339GO, "StateTests/RandomTests/st201503181339GO"} - declare_test!{StateTests_RandomTests_st201503181340GO, "StateTests/RandomTests/st201503181340GO"} - declare_test!{StateTests_RandomTests_st201503181341CPPJIT, "StateTests/RandomTests/st201503181341CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181342CPPJIT, "StateTests/RandomTests/st201503181342CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181342GO, "StateTests/RandomTests/st201503181342GO"} - declare_test!{StateTests_RandomTests_st201503181345GO, "StateTests/RandomTests/st201503181345GO"} - declare_test!{StateTests_RandomTests_st201503181346GO, "StateTests/RandomTests/st201503181346GO"} - declare_test!{StateTests_RandomTests_st201503181347CPPJIT, "StateTests/RandomTests/st201503181347CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181347GO, "StateTests/RandomTests/st201503181347GO"} - declare_test!{StateTests_RandomTests_st201503181347PYTHON, "StateTests/RandomTests/st201503181347PYTHON"} - declare_test!{StateTests_RandomTests_st201503181350CPPJIT, "StateTests/RandomTests/st201503181350CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181352GO, "StateTests/RandomTests/st201503181352GO"} - declare_test!{StateTests_RandomTests_st201503181353GO, "StateTests/RandomTests/st201503181353GO"} - declare_test!{StateTests_RandomTests_st201503181354CPPJIT, "StateTests/RandomTests/st201503181354CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181354GO, "StateTests/RandomTests/st201503181354GO"} - declare_test!{StateTests_RandomTests_st201503181355GO, "StateTests/RandomTests/st201503181355GO"} - declare_test!{StateTests_RandomTests_st201503181356CPPJIT, "StateTests/RandomTests/st201503181356CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181357CPPJIT, "StateTests/RandomTests/st201503181357CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181358CPPJIT, "StateTests/RandomTests/st201503181358CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181358GO, "StateTests/RandomTests/st201503181358GO"} - declare_test!{StateTests_RandomTests_st201503181359GO, "StateTests/RandomTests/st201503181359GO"} - declare_test!{StateTests_RandomTests_st201503181402CPPJIT, "StateTests/RandomTests/st201503181402CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181403GO, "StateTests/RandomTests/st201503181403GO"} - declare_test!{StateTests_RandomTests_st201503181406CPPJIT, "StateTests/RandomTests/st201503181406CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181406GO, "StateTests/RandomTests/st201503181406GO"} - declare_test!{StateTests_RandomTests_st201503181410GO, "StateTests/RandomTests/st201503181410GO"} - declare_test!{StateTests_RandomTests_st201503181412CPPJIT, "StateTests/RandomTests/st201503181412CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181413GO, "StateTests/RandomTests/st201503181413GO"} - declare_test!{StateTests_RandomTests_st201503181415GO, "StateTests/RandomTests/st201503181415GO"} - declare_test!{StateTests_RandomTests_st201503181416GO, "StateTests/RandomTests/st201503181416GO"} - declare_test!{StateTests_RandomTests_st201503181417CPPJIT, "StateTests/RandomTests/st201503181417CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181417GO, "StateTests/RandomTests/st201503181417GO"} - declare_test!{StateTests_RandomTests_st201503181418CPPJIT, "StateTests/RandomTests/st201503181418CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181422GO, "StateTests/RandomTests/st201503181422GO"} - declare_test!{StateTests_RandomTests_st201503181423CPPJIT, "StateTests/RandomTests/st201503181423CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181424GO, "StateTests/RandomTests/st201503181424GO"} - declare_test!{StateTests_RandomTests_st201503181426CPPJIT, "StateTests/RandomTests/st201503181426CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181426GO, "StateTests/RandomTests/st201503181426GO"} - declare_test!{StateTests_RandomTests_st201503181428GO, "StateTests/RandomTests/st201503181428GO"} - declare_test!{StateTests_RandomTests_st201503181430CPPJIT, "StateTests/RandomTests/st201503181430CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181435GO, "StateTests/RandomTests/st201503181435GO"} - declare_test!{StateTests_RandomTests_st201503181436GO, "StateTests/RandomTests/st201503181436GO"} - declare_test!{StateTests_RandomTests_st201503181437CPPJIT, "StateTests/RandomTests/st201503181437CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181437GO, "StateTests/RandomTests/st201503181437GO"} - declare_test!{StateTests_RandomTests_st201503181438CPPJIT, "StateTests/RandomTests/st201503181438CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181438GO, "StateTests/RandomTests/st201503181438GO"} - declare_test!{StateTests_RandomTests_st201503181439CPPJIT, "StateTests/RandomTests/st201503181439CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181439GO, "StateTests/RandomTests/st201503181439GO"} - declare_test!{StateTests_RandomTests_st201503181439PYTHON, "StateTests/RandomTests/st201503181439PYTHON"} - declare_test!{StateTests_RandomTests_st201503181440GO, "StateTests/RandomTests/st201503181440GO"} - declare_test!{StateTests_RandomTests_st201503181441GO, "StateTests/RandomTests/st201503181441GO"} - declare_test!{StateTests_RandomTests_st201503181442GO, "StateTests/RandomTests/st201503181442GO"} - declare_test!{StateTests_RandomTests_st201503181445CPPJIT, "StateTests/RandomTests/st201503181445CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181446GO, "StateTests/RandomTests/st201503181446GO"} - declare_test!{StateTests_RandomTests_st201503181447GO, "StateTests/RandomTests/st201503181447GO"} - declare_test!{StateTests_RandomTests_st201503181450GO, "StateTests/RandomTests/st201503181450GO"} - declare_test!{StateTests_RandomTests_st201503181451CPPJIT, "StateTests/RandomTests/st201503181451CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181453GO, "StateTests/RandomTests/st201503181453GO"} - declare_test!{StateTests_RandomTests_st201503181455GO, "StateTests/RandomTests/st201503181455GO"} - declare_test!{StateTests_RandomTests_st201503181456CPPJIT, "StateTests/RandomTests/st201503181456CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181457GO, "StateTests/RandomTests/st201503181457GO"} - declare_test!{StateTests_RandomTests_st201503181458GO, "StateTests/RandomTests/st201503181458GO"} - declare_test!{StateTests_RandomTests_st201503181459GO, "StateTests/RandomTests/st201503181459GO"} - declare_test!{StateTests_RandomTests_st201503181500GO, "StateTests/RandomTests/st201503181500GO"} - declare_test!{StateTests_RandomTests_st201503181501GO, "StateTests/RandomTests/st201503181501GO"} - declare_test!{StateTests_RandomTests_st201503181503GO, "StateTests/RandomTests/st201503181503GO"} - declare_test!{StateTests_RandomTests_st201503181504GO, "StateTests/RandomTests/st201503181504GO"} - declare_test!{StateTests_RandomTests_st201503181505GO, "StateTests/RandomTests/st201503181505GO"} - declare_test!{StateTests_RandomTests_st201503181506CPPJIT, "StateTests/RandomTests/st201503181506CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181507GO, "StateTests/RandomTests/st201503181507GO"} - declare_test!{StateTests_RandomTests_st201503181509CPPJIT, "StateTests/RandomTests/st201503181509CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181509GO, "StateTests/RandomTests/st201503181509GO"} - declare_test!{StateTests_RandomTests_st201503181510GO, "StateTests/RandomTests/st201503181510GO"} - declare_test!{StateTests_RandomTests_st201503181511GO, "StateTests/RandomTests/st201503181511GO"} - declare_test!{StateTests_RandomTests_st201503181512GO, "StateTests/RandomTests/st201503181512GO"} - declare_test!{StateTests_RandomTests_st201503181513CPPJIT, "StateTests/RandomTests/st201503181513CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181513GO, "StateTests/RandomTests/st201503181513GO"} - declare_test!{StateTests_RandomTests_st201503181514CPPJIT, "StateTests/RandomTests/st201503181514CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181514GO, "StateTests/RandomTests/st201503181514GO"} - declare_test!{StateTests_RandomTests_st201503181517CPPJIT, "StateTests/RandomTests/st201503181517CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181517GO, "StateTests/RandomTests/st201503181517GO"} - declare_test!{StateTests_RandomTests_st201503181519CPPJIT, "StateTests/RandomTests/st201503181519CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181519GO, "StateTests/RandomTests/st201503181519GO"} - declare_test!{StateTests_RandomTests_st201503181520CPPJIT, "StateTests/RandomTests/st201503181520CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181520GO, "StateTests/RandomTests/st201503181520GO"} - declare_test!{StateTests_RandomTests_st201503181521GO, "StateTests/RandomTests/st201503181521GO"} - declare_test!{StateTests_RandomTests_st201503181522GO, "StateTests/RandomTests/st201503181522GO"} - declare_test!{StateTests_RandomTests_st201503181524CPPJIT, "StateTests/RandomTests/st201503181524CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181524GO, "StateTests/RandomTests/st201503181524GO"} - declare_test!{StateTests_RandomTests_st201503181526GO, "StateTests/RandomTests/st201503181526GO"} - declare_test!{StateTests_RandomTests_st201503181527GO, "StateTests/RandomTests/st201503181527GO"} - declare_test!{StateTests_RandomTests_st201503181528CPPJIT, "StateTests/RandomTests/st201503181528CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181528GO, "StateTests/RandomTests/st201503181528GO"} - declare_test!{StateTests_RandomTests_st201503181528PYTHON, "StateTests/RandomTests/st201503181528PYTHON"} - declare_test!{StateTests_RandomTests_st201503181529GO, "StateTests/RandomTests/st201503181529GO"} - declare_test!{StateTests_RandomTests_st201503181531CPPJIT, "StateTests/RandomTests/st201503181531CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181533GO, "StateTests/RandomTests/st201503181533GO"} - declare_test!{StateTests_RandomTests_st201503181534CPPJIT, "StateTests/RandomTests/st201503181534CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181534GO, "StateTests/RandomTests/st201503181534GO"} - declare_test!{StateTests_RandomTests_st201503181536CPPJIT, "StateTests/RandomTests/st201503181536CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181536GO, "StateTests/RandomTests/st201503181536GO"} - declare_test!{StateTests_RandomTests_st201503181537GO, "StateTests/RandomTests/st201503181537GO"} - declare_test!{StateTests_RandomTests_st201503181538GO, "StateTests/RandomTests/st201503181538GO"} - declare_test!{StateTests_RandomTests_st201503181539GO, "StateTests/RandomTests/st201503181539GO"} - declare_test!{StateTests_RandomTests_st201503181540CPPJIT, "StateTests/RandomTests/st201503181540CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181540PYTHON, "StateTests/RandomTests/st201503181540PYTHON"} - declare_test!{StateTests_RandomTests_st201503181543GO, "StateTests/RandomTests/st201503181543GO"} - declare_test!{StateTests_RandomTests_st201503181544CPPJIT, "StateTests/RandomTests/st201503181544CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181544GO, "StateTests/RandomTests/st201503181544GO"} - declare_test!{StateTests_RandomTests_st201503181547GO, "StateTests/RandomTests/st201503181547GO"} - declare_test!{StateTests_RandomTests_st201503181548CPPJIT, "StateTests/RandomTests/st201503181548CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181548GO, "StateTests/RandomTests/st201503181548GO"} - declare_test!{StateTests_RandomTests_st201503181551GO, "StateTests/RandomTests/st201503181551GO"} - declare_test!{StateTests_RandomTests_st201503181552CPPJIT, "StateTests/RandomTests/st201503181552CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181553GO, "StateTests/RandomTests/st201503181553GO"} - declare_test!{StateTests_RandomTests_st201503181555CPPJIT, "StateTests/RandomTests/st201503181555CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181555GO, "StateTests/RandomTests/st201503181555GO"} - declare_test!{StateTests_RandomTests_st201503181557GO, "StateTests/RandomTests/st201503181557GO"} - declare_test!{StateTests_RandomTests_st201503181559GO, "StateTests/RandomTests/st201503181559GO"} - declare_test!{StateTests_RandomTests_st201503181601CPPJIT, "StateTests/RandomTests/st201503181601CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181601GO, "StateTests/RandomTests/st201503181601GO"} - declare_test!{StateTests_RandomTests_st201503181602GO, "StateTests/RandomTests/st201503181602GO"} - declare_test!{StateTests_RandomTests_st201503181603GO, "StateTests/RandomTests/st201503181603GO"} - declare_test!{StateTests_RandomTests_st201503181604GO, "StateTests/RandomTests/st201503181604GO"} - declare_test!{StateTests_RandomTests_st201503181605GO, "StateTests/RandomTests/st201503181605GO"} - declare_test!{StateTests_RandomTests_st201503181606GO, "StateTests/RandomTests/st201503181606GO"} - declare_test!{StateTests_RandomTests_st201503181607GO, "StateTests/RandomTests/st201503181607GO"} - declare_test!{StateTests_RandomTests_st201503181608CPPJIT, "StateTests/RandomTests/st201503181608CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181608GO, "StateTests/RandomTests/st201503181608GO"} - declare_test!{StateTests_RandomTests_st201503181609GO, "StateTests/RandomTests/st201503181609GO"} - declare_test!{StateTests_RandomTests_st201503181610CPPJIT, "StateTests/RandomTests/st201503181610CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181610GO, "StateTests/RandomTests/st201503181610GO"} - declare_test!{StateTests_RandomTests_st201503181611CPPJIT, "StateTests/RandomTests/st201503181611CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181611GO, "StateTests/RandomTests/st201503181611GO"} - declare_test!{StateTests_RandomTests_st201503181612GO, "StateTests/RandomTests/st201503181612GO"} - declare_test!{StateTests_RandomTests_st201503181614CPPJIT, "StateTests/RandomTests/st201503181614CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181614GO, "StateTests/RandomTests/st201503181614GO"} - declare_test!{StateTests_RandomTests_st201503181616CPPJIT, "StateTests/RandomTests/st201503181616CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181616GO, "StateTests/RandomTests/st201503181616GO"} - declare_test!{StateTests_RandomTests_st201503181617GO, "StateTests/RandomTests/st201503181617GO"} - declare_test!{StateTests_RandomTests_st201503181618GO, "StateTests/RandomTests/st201503181618GO"} - declare_test!{StateTests_RandomTests_st201503181619GO, "StateTests/RandomTests/st201503181619GO"} - declare_test!{StateTests_RandomTests_st201503181620CPPJIT, "StateTests/RandomTests/st201503181620CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181620GO, "StateTests/RandomTests/st201503181620GO"} - declare_test!{StateTests_RandomTests_st201503181621GO, "StateTests/RandomTests/st201503181621GO"} - declare_test!{StateTests_RandomTests_st201503181625GO, "StateTests/RandomTests/st201503181625GO"} - declare_test!{StateTests_RandomTests_st201503181626CPPJIT, "StateTests/RandomTests/st201503181626CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181626GO, "StateTests/RandomTests/st201503181626GO"} - declare_test!{StateTests_RandomTests_st201503181627GO, "StateTests/RandomTests/st201503181627GO"} - declare_test!{StateTests_RandomTests_st201503181628GO, "StateTests/RandomTests/st201503181628GO"} - declare_test!{StateTests_RandomTests_st201503181629GO, "StateTests/RandomTests/st201503181629GO"} - declare_test!{StateTests_RandomTests_st201503181630CPPJIT, "StateTests/RandomTests/st201503181630CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181630GO, "StateTests/RandomTests/st201503181630GO"} - declare_test!{StateTests_RandomTests_st201503181630PYTHON, "StateTests/RandomTests/st201503181630PYTHON"} - declare_test!{StateTests_RandomTests_st201503181632GO, "StateTests/RandomTests/st201503181632GO"} - declare_test!{StateTests_RandomTests_st201503181634CPPJIT, "StateTests/RandomTests/st201503181634CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181635GO, "StateTests/RandomTests/st201503181635GO"} - declare_test!{StateTests_RandomTests_st201503181636GO, "StateTests/RandomTests/st201503181636GO"} - declare_test!{StateTests_RandomTests_st201503181638GO, "StateTests/RandomTests/st201503181638GO"} - declare_test!{StateTests_RandomTests_st201503181639CPPJIT, "StateTests/RandomTests/st201503181639CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181641GO, "StateTests/RandomTests/st201503181641GO"} - declare_test!{StateTests_RandomTests_st201503181645GO, "StateTests/RandomTests/st201503181645GO"} - declare_test!{StateTests_RandomTests_st201503181646GO, "StateTests/RandomTests/st201503181646GO"} - declare_test!{StateTests_RandomTests_st201503181647CPPJIT, "StateTests/RandomTests/st201503181647CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181649CPPJIT, "StateTests/RandomTests/st201503181649CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181650GO, "StateTests/RandomTests/st201503181650GO"} - declare_test!{StateTests_RandomTests_st201503181652CPPJIT, "StateTests/RandomTests/st201503181652CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181653GO, "StateTests/RandomTests/st201503181653GO"} - declare_test!{StateTests_RandomTests_st201503181654GO, "StateTests/RandomTests/st201503181654GO"} - declare_test!{StateTests_RandomTests_st201503181655CPPJIT, "StateTests/RandomTests/st201503181655CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181655GO, "StateTests/RandomTests/st201503181655GO"} - declare_test!{StateTests_RandomTests_st201503181656CPPJIT, "StateTests/RandomTests/st201503181656CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181656GO, "StateTests/RandomTests/st201503181656GO"} - declare_test!{StateTests_RandomTests_st201503181657GO, "StateTests/RandomTests/st201503181657GO"} - declare_test!{StateTests_RandomTests_st201503181658GO, "StateTests/RandomTests/st201503181658GO"} - declare_test!{StateTests_RandomTests_st201503181700GO, "StateTests/RandomTests/st201503181700GO"} - declare_test!{StateTests_RandomTests_st201503181702GO, "StateTests/RandomTests/st201503181702GO"} - declare_test!{StateTests_RandomTests_st201503181703CPPJIT, "StateTests/RandomTests/st201503181703CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181703GO, "StateTests/RandomTests/st201503181703GO"} - declare_test!{StateTests_RandomTests_st201503181704GO, "StateTests/RandomTests/st201503181704GO"} - declare_test!{StateTests_RandomTests_st201503181706GO, "StateTests/RandomTests/st201503181706GO"} - declare_test!{StateTests_RandomTests_st201503181709GO, "StateTests/RandomTests/st201503181709GO"} - declare_test!{StateTests_RandomTests_st201503181711CPPJIT, "StateTests/RandomTests/st201503181711CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181711GO, "StateTests/RandomTests/st201503181711GO"} - declare_test!{StateTests_RandomTests_st201503181713CPPJIT, "StateTests/RandomTests/st201503181713CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181713GO, "StateTests/RandomTests/st201503181713GO"} - declare_test!{StateTests_RandomTests_st201503181714GO, "StateTests/RandomTests/st201503181714GO"} - declare_test!{StateTests_RandomTests_st201503181715CPPJIT, "StateTests/RandomTests/st201503181715CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181715GO, "StateTests/RandomTests/st201503181715GO"} - declare_test!{StateTests_RandomTests_st201503181716GO, "StateTests/RandomTests/st201503181716GO"} - declare_test!{StateTests_RandomTests_st201503181717GO, "StateTests/RandomTests/st201503181717GO"} - declare_test!{StateTests_RandomTests_st201503181720CPPJIT, "StateTests/RandomTests/st201503181720CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181722GO, "StateTests/RandomTests/st201503181722GO"} - declare_test!{StateTests_RandomTests_st201503181723CPPJIT, "StateTests/RandomTests/st201503181723CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181723GO, "StateTests/RandomTests/st201503181723GO"} - declare_test!{StateTests_RandomTests_st201503181724CPPJIT, "StateTests/RandomTests/st201503181724CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181724GO, "StateTests/RandomTests/st201503181724GO"} - declare_test!{StateTests_RandomTests_st201503181725GO, "StateTests/RandomTests/st201503181725GO"} - declare_test!{StateTests_RandomTests_st201503181728GO, "StateTests/RandomTests/st201503181728GO"} - declare_test!{StateTests_RandomTests_st201503181729GO, "StateTests/RandomTests/st201503181729GO"} - declare_test!{StateTests_RandomTests_st201503181730GO, "StateTests/RandomTests/st201503181730GO"} - declare_test!{StateTests_RandomTests_st201503181731CPPJIT, "StateTests/RandomTests/st201503181731CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181732GO, "StateTests/RandomTests/st201503181732GO"} - declare_test!{StateTests_RandomTests_st201503181734CPPJIT, "StateTests/RandomTests/st201503181734CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181734GO, "StateTests/RandomTests/st201503181734GO"} - declare_test!{StateTests_RandomTests_st201503181735GO, "StateTests/RandomTests/st201503181735GO"} - declare_test!{StateTests_RandomTests_st201503181737CPPJIT, "StateTests/RandomTests/st201503181737CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181737GO, "StateTests/RandomTests/st201503181737GO"} - declare_test!{StateTests_RandomTests_st201503181738CPPJIT, "StateTests/RandomTests/st201503181738CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181738GO, "StateTests/RandomTests/st201503181738GO"} - declare_test!{StateTests_RandomTests_st201503181739GO, "StateTests/RandomTests/st201503181739GO"} - declare_test!{StateTests_RandomTests_st201503181740CPPJIT, "StateTests/RandomTests/st201503181740CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181740GO, "StateTests/RandomTests/st201503181740GO"} - declare_test!{StateTests_RandomTests_st201503181742CPPJIT, "StateTests/RandomTests/st201503181742CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181743GO, "StateTests/RandomTests/st201503181743GO"} - declare_test!{StateTests_RandomTests_st201503181744GO, "StateTests/RandomTests/st201503181744GO"} - declare_test!{StateTests_RandomTests_st201503181745CPPJIT, "StateTests/RandomTests/st201503181745CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181746GO, "StateTests/RandomTests/st201503181746GO"} - declare_test!{StateTests_RandomTests_st201503181747GO, "StateTests/RandomTests/st201503181747GO"} - declare_test!{StateTests_RandomTests_st201503181748GO, "StateTests/RandomTests/st201503181748GO"} - declare_test!{StateTests_RandomTests_st201503181749GO, "StateTests/RandomTests/st201503181749GO"} - declare_test!{StateTests_RandomTests_st201503181750CPPJIT, "StateTests/RandomTests/st201503181750CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181750GO, "StateTests/RandomTests/st201503181750GO"} - declare_test!{StateTests_RandomTests_st201503181752GO, "StateTests/RandomTests/st201503181752GO"} - declare_test!{StateTests_RandomTests_st201503181753CPPJIT, "StateTests/RandomTests/st201503181753CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181754CPPJIT, "StateTests/RandomTests/st201503181754CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181754GO, "StateTests/RandomTests/st201503181754GO"} - declare_test!{StateTests_RandomTests_st201503181755CPPJIT, "StateTests/RandomTests/st201503181755CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181755GO, "StateTests/RandomTests/st201503181755GO"} - declare_test!{StateTests_RandomTests_st201503181756GO, "StateTests/RandomTests/st201503181756GO"} - declare_test!{StateTests_RandomTests_st201503181757CPPJIT, "StateTests/RandomTests/st201503181757CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181757GO, "StateTests/RandomTests/st201503181757GO"} - declare_test!{StateTests_RandomTests_st201503181759GO, "StateTests/RandomTests/st201503181759GO"} - declare_test!{StateTests_RandomTests_st201503181800GO, "StateTests/RandomTests/st201503181800GO"} - declare_test!{StateTests_RandomTests_st201503181801GO, "StateTests/RandomTests/st201503181801GO"} - declare_test!{StateTests_RandomTests_st201503181802GO, "StateTests/RandomTests/st201503181802GO"} - declare_test!{StateTests_RandomTests_st201503181803CPPJIT, "StateTests/RandomTests/st201503181803CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181803GO, "StateTests/RandomTests/st201503181803GO"} - declare_test!{StateTests_RandomTests_st201503181804GO, "StateTests/RandomTests/st201503181804GO"} - declare_test!{StateTests_RandomTests_st201503181806GO, "StateTests/RandomTests/st201503181806GO"} - declare_test!{StateTests_RandomTests_st201503181808GO, "StateTests/RandomTests/st201503181808GO"} - declare_test!{StateTests_RandomTests_st201503181809CPPJIT, "StateTests/RandomTests/st201503181809CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181812CPPJIT, "StateTests/RandomTests/st201503181812CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181812GO, "StateTests/RandomTests/st201503181812GO"} - declare_test!{StateTests_RandomTests_st201503181814CPPJIT, "StateTests/RandomTests/st201503181814CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181815GO, "StateTests/RandomTests/st201503181815GO"} - declare_test!{StateTests_RandomTests_st201503181816CPPJIT, "StateTests/RandomTests/st201503181816CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181817CPPJIT, "StateTests/RandomTests/st201503181817CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181819GO, "StateTests/RandomTests/st201503181819GO"} - declare_test!{StateTests_RandomTests_st201503181821GO, "StateTests/RandomTests/st201503181821GO"} - declare_test!{StateTests_RandomTests_st201503181822GO, "StateTests/RandomTests/st201503181822GO"} - declare_test!{StateTests_RandomTests_st201503181823GO, "StateTests/RandomTests/st201503181823GO"} - declare_test!{StateTests_RandomTests_st201503181824GO, "StateTests/RandomTests/st201503181824GO"} - declare_test!{StateTests_RandomTests_st201503181825GO, "StateTests/RandomTests/st201503181825GO"} - declare_test!{StateTests_RandomTests_st201503181829GO, "StateTests/RandomTests/st201503181829GO"} - declare_test!{StateTests_RandomTests_st201503181830CPPJIT, "StateTests/RandomTests/st201503181830CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181833GO, "StateTests/RandomTests/st201503181833GO"} - declare_test!{StateTests_RandomTests_st201503181834CPPJIT, "StateTests/RandomTests/st201503181834CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181834GO, "StateTests/RandomTests/st201503181834GO"} - declare_test!{StateTests_RandomTests_st201503181837GO, "StateTests/RandomTests/st201503181837GO"} - declare_test!{StateTests_RandomTests_st201503181840GO, "StateTests/RandomTests/st201503181840GO"} - declare_test!{StateTests_RandomTests_st201503181842GO, "StateTests/RandomTests/st201503181842GO"} - declare_test!{StateTests_RandomTests_st201503181843GO, "StateTests/RandomTests/st201503181843GO"} - declare_test!{StateTests_RandomTests_st201503181844GO, "StateTests/RandomTests/st201503181844GO"} - declare_test!{StateTests_RandomTests_st201503181845GO, "StateTests/RandomTests/st201503181845GO"} - declare_test!{StateTests_RandomTests_st201503181846GO, "StateTests/RandomTests/st201503181846GO"} - declare_test!{StateTests_RandomTests_st201503181847GO, "StateTests/RandomTests/st201503181847GO"} - declare_test!{StateTests_RandomTests_st201503181848GO, "StateTests/RandomTests/st201503181848GO"} - declare_test!{StateTests_RandomTests_st201503181849GO, "StateTests/RandomTests/st201503181849GO"} - declare_test!{StateTests_RandomTests_st201503181850GO, "StateTests/RandomTests/st201503181850GO"} - declare_test!{StateTests_RandomTests_st201503181851CPPJIT, "StateTests/RandomTests/st201503181851CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181851GO, "StateTests/RandomTests/st201503181851GO"} - declare_test!{StateTests_RandomTests_st201503181852CPPJIT, "StateTests/RandomTests/st201503181852CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181854GO, "StateTests/RandomTests/st201503181854GO"} - declare_test!{StateTests_RandomTests_st201503181855CPPJIT, "StateTests/RandomTests/st201503181855CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181857PYTHON, "StateTests/RandomTests/st201503181857PYTHON"} - declare_test!{StateTests_RandomTests_st201503181859GO, "StateTests/RandomTests/st201503181859GO"} - declare_test!{StateTests_RandomTests_st201503181900GO, "StateTests/RandomTests/st201503181900GO"} - declare_test!{StateTests_RandomTests_st201503181903GO, "StateTests/RandomTests/st201503181903GO"} - declare_test!{StateTests_RandomTests_st201503181904GO, "StateTests/RandomTests/st201503181904GO"} - declare_test!{StateTests_RandomTests_st201503181906GO, "StateTests/RandomTests/st201503181906GO"} - declare_test!{StateTests_RandomTests_st201503181907GO, "StateTests/RandomTests/st201503181907GO"} - declare_test!{StateTests_RandomTests_st201503181910GO, "StateTests/RandomTests/st201503181910GO"} - declare_test!{StateTests_RandomTests_st201503181915GO, "StateTests/RandomTests/st201503181915GO"} - declare_test!{StateTests_RandomTests_st201503181919CPPJIT, "StateTests/RandomTests/st201503181919CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181919PYTHON, "StateTests/RandomTests/st201503181919PYTHON"} - declare_test!{StateTests_RandomTests_st201503181920GO, "StateTests/RandomTests/st201503181920GO"} - declare_test!{StateTests_RandomTests_st201503181922GO, "StateTests/RandomTests/st201503181922GO"} - declare_test!{StateTests_RandomTests_st201503181926GO, "StateTests/RandomTests/st201503181926GO"} - declare_test!{StateTests_RandomTests_st201503181929GO, "StateTests/RandomTests/st201503181929GO"} - declare_test!{StateTests_RandomTests_st201503181931CPPJIT, "StateTests/RandomTests/st201503181931CPPJIT"} - declare_test!{StateTests_RandomTests_st201503181931GO, "StateTests/RandomTests/st201503181931GO"} - declare_test!{StateTests_RandomTests_st201503181931PYTHON, "StateTests/RandomTests/st201503181931PYTHON"} - declare_test!{StateTests_RandomTests_st201503191646GO, "StateTests/RandomTests/st201503191646GO"} - declare_test!{StateTests_RandomTests_st201503200837JS, "StateTests/RandomTests/st201503200837JS"} - declare_test!{StateTests_RandomTests_st201503200838JS, "StateTests/RandomTests/st201503200838JS"} - declare_test!{StateTests_RandomTests_st201503200841JS, "StateTests/RandomTests/st201503200841JS"} - declare_test!{StateTests_RandomTests_st201503200848JS, "StateTests/RandomTests/st201503200848JS"} - declare_test!{StateTests_RandomTests_st201503240609JS, "StateTests/RandomTests/st201503240609JS"} - declare_test!{StateTests_RandomTests_st201503302200JS, "StateTests/RandomTests/st201503302200JS"} - declare_test!{StateTests_RandomTests_st201503302202JS, "StateTests/RandomTests/st201503302202JS"} - declare_test!{StateTests_RandomTests_st201503302206JS, "StateTests/RandomTests/st201503302206JS"} - declare_test!{StateTests_RandomTests_st201503302208JS, "StateTests/RandomTests/st201503302208JS"} - declare_test!{StateTests_RandomTests_st201503302210JS, "StateTests/RandomTests/st201503302210JS"} - declare_test!{StateTests_RandomTests_st201503302211JS, "StateTests/RandomTests/st201503302211JS"} - declare_test!{StateTests_RandomTests_st201504011535GO, "StateTests/RandomTests/st201504011535GO"} - declare_test!{StateTests_RandomTests_st201504011536GO, "StateTests/RandomTests/st201504011536GO"} - declare_test!{StateTests_RandomTests_st201504011547GO, "StateTests/RandomTests/st201504011547GO"} - declare_test!{StateTests_RandomTests_st201504011916JS, "StateTests/RandomTests/st201504011916JS"} - declare_test!{StateTests_RandomTests_st201504012130JS, "StateTests/RandomTests/st201504012130JS"} - declare_test!{StateTests_RandomTests_st201504012259JS, "StateTests/RandomTests/st201504012259JS"} - declare_test!{StateTests_RandomTests_st201504012359JS, "StateTests/RandomTests/st201504012359JS"} - declare_test!{StateTests_RandomTests_st201504020305JS, "StateTests/RandomTests/st201504020305JS"} - declare_test!{StateTests_RandomTests_st201504020400JS, "StateTests/RandomTests/st201504020400JS"} - declare_test!{StateTests_RandomTests_st201504020428JS, "StateTests/RandomTests/st201504020428JS"} - declare_test!{StateTests_RandomTests_st201504020431JS, "StateTests/RandomTests/st201504020431JS"} - declare_test!{StateTests_RandomTests_st201504020444JS, "StateTests/RandomTests/st201504020444JS"} - declare_test!{StateTests_RandomTests_st201504020538JS, "StateTests/RandomTests/st201504020538JS"} - declare_test!{StateTests_RandomTests_st201504020639JS, "StateTests/RandomTests/st201504020639JS"} - declare_test!{StateTests_RandomTests_st201504020836JS, "StateTests/RandomTests/st201504020836JS"} - declare_test!{StateTests_RandomTests_st201504020910JS, "StateTests/RandomTests/st201504020910JS"} - declare_test!{StateTests_RandomTests_st201504021057JS, "StateTests/RandomTests/st201504021057JS"} - declare_test!{StateTests_RandomTests_st201504021104JS, "StateTests/RandomTests/st201504021104JS"} - declare_test!{StateTests_RandomTests_st201504021237CPPJIT, "StateTests/RandomTests/st201504021237CPPJIT"} - declare_test!{StateTests_RandomTests_st201504021237GO, "StateTests/RandomTests/st201504021237GO"} - declare_test!{StateTests_RandomTests_st201504021237JS, "StateTests/RandomTests/st201504021237JS"} - declare_test!{StateTests_RandomTests_st201504021237PYTHON, "StateTests/RandomTests/st201504021237PYTHON"} - declare_test!{StateTests_RandomTests_st201504021949JS, "StateTests/RandomTests/st201504021949JS"} - declare_test!{StateTests_RandomTests_st201504022003CPPJIT, "StateTests/RandomTests/st201504022003CPPJIT"} - declare_test!{StateTests_RandomTests_st201504022124JS, "StateTests/RandomTests/st201504022124JS"} - declare_test!{StateTests_RandomTests_st201504030138JS, "StateTests/RandomTests/st201504030138JS"} - declare_test!{StateTests_RandomTests_st201504030646JS, "StateTests/RandomTests/st201504030646JS"} - declare_test!{StateTests_RandomTests_st201504030709JS, "StateTests/RandomTests/st201504030709JS"} - declare_test!{StateTests_RandomTests_st201504031133JS, "StateTests/RandomTests/st201504031133JS"} - declare_test!{StateTests_RandomTests_st201504031446JS, "StateTests/RandomTests/st201504031446JS"} - declare_test!{StateTests_RandomTests_st201504031841JS, "StateTests/RandomTests/st201504031841JS"} - declare_test!{StateTests_RandomTests_st201504041605JS, "StateTests/RandomTests/st201504041605JS"} - declare_test!{StateTests_RandomTests_st201504042052JS, "StateTests/RandomTests/st201504042052JS"} - declare_test!{StateTests_RandomTests_st201504042226CPPJIT, "StateTests/RandomTests/st201504042226CPPJIT"} - declare_test!{StateTests_RandomTests_st201504042355CPPJIT, "StateTests/RandomTests/st201504042355CPPJIT"} - declare_test!{StateTests_RandomTests_st201504050059JS, "StateTests/RandomTests/st201504050059JS"} - declare_test!{StateTests_RandomTests_st201504050733JS, "StateTests/RandomTests/st201504050733JS"} - declare_test!{StateTests_RandomTests_st201504051540JS, "StateTests/RandomTests/st201504051540JS"} - declare_test!{StateTests_RandomTests_st201504051944CPPJIT, "StateTests/RandomTests/st201504051944CPPJIT"} - declare_test!{StateTests_RandomTests_st201504052008CPPJIT, "StateTests/RandomTests/st201504052008CPPJIT"} - declare_test!{StateTests_RandomTests_st201504052014GO, "StateTests/RandomTests/st201504052014GO"} - declare_test!{StateTests_RandomTests_st201504052031CPPJIT, "StateTests/RandomTests/st201504052031CPPJIT"} - declare_test!{StateTests_RandomTests_st201504060057CPPJIT, "StateTests/RandomTests/st201504060057CPPJIT"} - declare_test!{StateTests_RandomTests_st201504060418CPPJIT, "StateTests/RandomTests/st201504060418CPPJIT"} - declare_test!{StateTests_RandomTests_st201504061106CPPJIT, "StateTests/RandomTests/st201504061106CPPJIT"} - declare_test!{StateTests_RandomTests_st201504061134CPPJIT, "StateTests/RandomTests/st201504061134CPPJIT"} - declare_test!{StateTests_RandomTests_st201504062033CPPJIT, "StateTests/RandomTests/st201504062033CPPJIT"} - declare_test!{StateTests_RandomTests_st201504062046CPPJIT, "StateTests/RandomTests/st201504062046CPPJIT"} - declare_test!{StateTests_RandomTests_st201504062314CPPJIT, "StateTests/RandomTests/st201504062314CPPJIT"} - declare_test!{StateTests_RandomTests_st201504070746JS, "StateTests/RandomTests/st201504070746JS"} - declare_test!{StateTests_RandomTests_st201504070816CPPJIT, "StateTests/RandomTests/st201504070816CPPJIT"} - declare_test!{StateTests_RandomTests_st201504070836CPPJIT, "StateTests/RandomTests/st201504070836CPPJIT"} - declare_test!{StateTests_RandomTests_st201504070839CPPJIT, "StateTests/RandomTests/st201504070839CPPJIT"} - declare_test!{StateTests_RandomTests_st201504071041CPPJIT, "StateTests/RandomTests/st201504071041CPPJIT"} - declare_test!{StateTests_RandomTests_st201504071056CPPJIT, "StateTests/RandomTests/st201504071056CPPJIT"} - declare_test!{StateTests_RandomTests_st201504071621CPPJIT, "StateTests/RandomTests/st201504071621CPPJIT"} - declare_test!{StateTests_RandomTests_st201504071653CPPJIT, "StateTests/RandomTests/st201504071653CPPJIT"} - declare_test!{StateTests_RandomTests_st201504071750CPPJIT, "StateTests/RandomTests/st201504071750CPPJIT"} - declare_test!{StateTests_RandomTests_st201504071905CPPJIT, "StateTests/RandomTests/st201504071905CPPJIT"} - declare_test!{StateTests_RandomTests_st201504080454CPPJIT, "StateTests/RandomTests/st201504080454CPPJIT"} - declare_test!{StateTests_RandomTests_st201504080457CPPJIT, "StateTests/RandomTests/st201504080457CPPJIT"} - declare_test!{StateTests_RandomTests_st201504080650CPPJIT, "StateTests/RandomTests/st201504080650CPPJIT"} - declare_test!{StateTests_RandomTests_st201504080840CPPJIT, "StateTests/RandomTests/st201504080840CPPJIT"} - declare_test!{StateTests_RandomTests_st201504080948CPPJIT, "StateTests/RandomTests/st201504080948CPPJIT"} - declare_test!{StateTests_RandomTests_st201504081100CPPJIT, "StateTests/RandomTests/st201504081100CPPJIT"} - declare_test!{StateTests_RandomTests_st201504081134CPPJIT, "StateTests/RandomTests/st201504081134CPPJIT"} - declare_test!{StateTests_RandomTests_st201504081138CPPJIT, "StateTests/RandomTests/st201504081138CPPJIT"} - declare_test!{StateTests_RandomTests_st201504081611CPPJIT, "StateTests/RandomTests/st201504081611CPPJIT"} - declare_test!{StateTests_RandomTests_st201504081841JAVA, "StateTests/RandomTests/st201504081841JAVA"} - declare_test!{StateTests_RandomTests_st201504081842JAVA, "StateTests/RandomTests/st201504081842JAVA"} - declare_test!{StateTests_RandomTests_st201504081843JAVA, "StateTests/RandomTests/st201504081843JAVA"} - declare_test!{StateTests_RandomTests_st201504081928CPPJIT, "StateTests/RandomTests/st201504081928CPPJIT"} - declare_test!{StateTests_RandomTests_st201504081953JAVA, "StateTests/RandomTests/st201504081953JAVA"} - declare_test!{StateTests_RandomTests_st201504081954JAVA, "StateTests/RandomTests/st201504081954JAVA"} - declare_test!{StateTests_RandomTests_st201504081955JAVA, "StateTests/RandomTests/st201504081955JAVA"} - declare_test!{StateTests_RandomTests_st201504081956JAVA, "StateTests/RandomTests/st201504081956JAVA"} - declare_test!{StateTests_RandomTests_st201504081957JAVA, "StateTests/RandomTests/st201504081957JAVA"} - declare_test!{StateTests_RandomTests_st201504082000JAVA, "StateTests/RandomTests/st201504082000JAVA"} - declare_test!{StateTests_RandomTests_st201504082001JAVA, "StateTests/RandomTests/st201504082001JAVA"} - declare_test!{StateTests_RandomTests_st201504082002JAVA, "StateTests/RandomTests/st201504082002JAVA"} - declare_test!{StateTests_RandomTests_st201504090553CPPJIT, "StateTests/RandomTests/st201504090553CPPJIT"} - declare_test!{StateTests_RandomTests_st201504090657CPPJIT, "StateTests/RandomTests/st201504090657CPPJIT"} - declare_test!{StateTests_RandomTests_st201504091403CPPJIT, "StateTests/RandomTests/st201504091403CPPJIT"} - declare_test!{StateTests_RandomTests_st201504091641CPPJIT, "StateTests/RandomTests/st201504091641CPPJIT"} - declare_test!{StateTests_RandomTests_st201504092303CPPJIT, "StateTests/RandomTests/st201504092303CPPJIT"} - declare_test!{StateTests_RandomTests_st201504100125CPPJIT, "StateTests/RandomTests/st201504100125CPPJIT"} - declare_test!{StateTests_RandomTests_st201504100215CPPJIT, "StateTests/RandomTests/st201504100215CPPJIT"} - declare_test!{StateTests_RandomTests_st201504100226PYTHON, "StateTests/RandomTests/st201504100226PYTHON"} - declare_test!{StateTests_RandomTests_st201504100308CPPJIT, "StateTests/RandomTests/st201504100308CPPJIT"} - declare_test!{StateTests_RandomTests_st201504100337CPPJIT, "StateTests/RandomTests/st201504100337CPPJIT"} - declare_test!{StateTests_RandomTests_st201504100341CPPJIT, "StateTests/RandomTests/st201504100341CPPJIT"} - declare_test!{StateTests_RandomTests_st201504101009CPPJIT, "StateTests/RandomTests/st201504101009CPPJIT"} - declare_test!{StateTests_RandomTests_st201504101150CPPJIT, "StateTests/RandomTests/st201504101150CPPJIT"} - declare_test!{StateTests_RandomTests_st201504101223CPPJIT, "StateTests/RandomTests/st201504101223CPPJIT"} - declare_test!{StateTests_RandomTests_st201504101338CPPJIT, "StateTests/RandomTests/st201504101338CPPJIT"} - declare_test!{StateTests_RandomTests_st201504101754PYTHON, "StateTests/RandomTests/st201504101754PYTHON"} - declare_test!{StateTests_RandomTests_st201504111554CPPJIT, "StateTests/RandomTests/st201504111554CPPJIT"} - declare_test!{StateTests_RandomTests_st201504130653JS, "StateTests/RandomTests/st201504130653JS"} - declare_test!{StateTests_RandomTests_st201504131821CPPJIT, "StateTests/RandomTests/st201504131821CPPJIT"} - declare_test!{StateTests_RandomTests_st201504140229CPPJIT, "StateTests/RandomTests/st201504140229CPPJIT"} - declare_test!{StateTests_RandomTests_st201504140236CPPJIT, "StateTests/RandomTests/st201504140236CPPJIT"} - declare_test!{StateTests_RandomTests_st201504140359CPPJIT, "StateTests/RandomTests/st201504140359CPPJIT"} - declare_test!{StateTests_RandomTests_st201504140750CPPJIT, "StateTests/RandomTests/st201504140750CPPJIT"} - declare_test!{StateTests_RandomTests_st201504140818CPPJIT, "StateTests/RandomTests/st201504140818CPPJIT"} - declare_test!{StateTests_RandomTests_st201504140900CPPJIT, "StateTests/RandomTests/st201504140900CPPJIT"} - declare_test!{StateTests_RandomTests_st201504150854CPPJIT, "StateTests/RandomTests/st201504150854CPPJIT"} - declare_test!{StateTests_RandomTests_st201504151057CPPJIT, "StateTests/RandomTests/st201504151057CPPJIT"} - declare_test!{StateTests_RandomTests_st201504202124CPPJIT, "StateTests/RandomTests/st201504202124CPPJIT"} - declare_test!{StateTests_RandomTests_st201504210245CPPJIT, "StateTests/RandomTests/st201504210245CPPJIT"} - declare_test!{StateTests_RandomTests_st201504210957CPPJIT, "StateTests/RandomTests/st201504210957CPPJIT"} - declare_test!{StateTests_RandomTests_st201504211739CPPJIT, "StateTests/RandomTests/st201504211739CPPJIT"} - declare_test!{StateTests_RandomTests_st201504212038CPPJIT, "StateTests/RandomTests/st201504212038CPPJIT"} - declare_test!{StateTests_RandomTests_st201504230729CPPJIT, "StateTests/RandomTests/st201504230729CPPJIT"} - declare_test!{StateTests_RandomTests_st201504231639CPPJIT, "StateTests/RandomTests/st201504231639CPPJIT"} - declare_test!{StateTests_RandomTests_st201504231710CPPJIT, "StateTests/RandomTests/st201504231710CPPJIT"} - declare_test!{StateTests_RandomTests_st201504231742CPPJIT, "StateTests/RandomTests/st201504231742CPPJIT"} - declare_test!{StateTests_RandomTests_st201504232350CPPJIT, "StateTests/RandomTests/st201504232350CPPJIT"} - declare_test!{StateTests_RandomTests_st201504240140CPPJIT, "StateTests/RandomTests/st201504240140CPPJIT"} - declare_test!{StateTests_RandomTests_st201504240220CPPJIT, "StateTests/RandomTests/st201504240220CPPJIT"} - declare_test!{StateTests_RandomTests_st201504240351CPPJIT, "StateTests/RandomTests/st201504240351CPPJIT"} - declare_test!{StateTests_RandomTests_st201504240817CPPJIT, "StateTests/RandomTests/st201504240817CPPJIT"} - declare_test!{StateTests_RandomTests_st201504241118CPPJIT, "StateTests/RandomTests/st201504241118CPPJIT"} - declare_test!{StateTests_RandomTests_st201505021810CPPJIT, "StateTests/RandomTests/st201505021810CPPJIT"} - declare_test!{StateTests_RandomTests_st201505050557JS, "StateTests/RandomTests/st201505050557JS"} - declare_test!{StateTests_RandomTests_st201505050929GO, "StateTests/RandomTests/st201505050929GO"} - declare_test!{StateTests_RandomTests_st201505050942PYTHON, "StateTests/RandomTests/st201505050942PYTHON"} - declare_test!{StateTests_RandomTests_st201505051004PYTHON, "StateTests/RandomTests/st201505051004PYTHON"} - declare_test!{StateTests_RandomTests_st201505051016PYTHON, "StateTests/RandomTests/st201505051016PYTHON"} - declare_test!{StateTests_RandomTests_st201505051114GO, "StateTests/RandomTests/st201505051114GO"} - declare_test!{StateTests_RandomTests_st201505051238GO, "StateTests/RandomTests/st201505051238GO"} - declare_test!{StateTests_RandomTests_st201505051249GO, "StateTests/RandomTests/st201505051249GO"} - declare_test!{StateTests_RandomTests_st201505051558PYTHON, "StateTests/RandomTests/st201505051558PYTHON"} - declare_test!{StateTests_RandomTests_st201505051611PYTHON, "StateTests/RandomTests/st201505051611PYTHON"} - declare_test!{StateTests_RandomTests_st201505051648JS, "StateTests/RandomTests/st201505051648JS"} - declare_test!{StateTests_RandomTests_st201505051710GO, "StateTests/RandomTests/st201505051710GO"} - declare_test!{StateTests_RandomTests_st201505052013GO, "StateTests/RandomTests/st201505052013GO"} - declare_test!{StateTests_RandomTests_st201505052102JS, "StateTests/RandomTests/st201505052102JS"} - declare_test!{StateTests_RandomTests_st201505052235GO, "StateTests/RandomTests/st201505052235GO"} - declare_test!{StateTests_RandomTests_st201505052238JS, "StateTests/RandomTests/st201505052238JS"} - declare_test!{StateTests_RandomTests_st201505052242PYTHON, "StateTests/RandomTests/st201505052242PYTHON"} - declare_test!{StateTests_RandomTests_st201505052343PYTHON, "StateTests/RandomTests/st201505052343PYTHON"} - declare_test!{StateTests_RandomTests_st201505060120GO, "StateTests/RandomTests/st201505060120GO"} - declare_test!{StateTests_RandomTests_st201505060121GO, "StateTests/RandomTests/st201505060121GO"} - declare_test!{StateTests_RandomTests_st201505060136PYTHON, "StateTests/RandomTests/st201505060136PYTHON"} - declare_test!{StateTests_RandomTests_st201505060646JS, "StateTests/RandomTests/st201505060646JS"} - declare_test!{StateTests_RandomTests_st201505252314CPPJIT, "StateTests/RandomTests/st201505252314CPPJIT"} - declare_test!{StateTests_RandomTests_st201505272131CPPJIT, "StateTests/RandomTests/st201505272131CPPJIT"} - declare_test!{StateTests_RandomTests_st201506040034GO, "StateTests/RandomTests/st201506040034GO"} - declare_test!{StateTests_RandomTests_st201506040157GO, "StateTests/RandomTests/st201506040157GO"} - declare_test!{StateTests_RandomTests_st201506052130GO, "StateTests/RandomTests/st201506052130GO"} - declare_test!{StateTests_RandomTests_st201506060929GO, "StateTests/RandomTests/st201506060929GO"} - declare_test!{StateTests_RandomTests_st201506061255GO, "StateTests/RandomTests/st201506061255GO"} - declare_test!{StateTests_RandomTests_st201506062331GO, "StateTests/RandomTests/st201506062331GO"} - declare_test!{StateTests_RandomTests_st201506070548GO, "StateTests/RandomTests/st201506070548GO"} - declare_test!{StateTests_RandomTests_st201506071050GO, "StateTests/RandomTests/st201506071050GO"} - declare_test!{StateTests_RandomTests_st201506071624GO, "StateTests/RandomTests/st201506071624GO"} - declare_test!{StateTests_RandomTests_st201506071819GO, "StateTests/RandomTests/st201506071819GO"} - declare_test!{StateTests_RandomTests_st201506072007GO, "StateTests/RandomTests/st201506072007GO"} - declare_test!{StateTests_RandomTests_st201506080556GO, "StateTests/RandomTests/st201506080556GO"} - declare_test!{StateTests_RandomTests_st201506080721GO, "StateTests/RandomTests/st201506080721GO"} - declare_test!{StateTests_RandomTests_st201506091836GO, "StateTests/RandomTests/st201506091836GO"} - declare_test!{StateTests_RandomTests_st201506092032GO, "StateTests/RandomTests/st201506092032GO"} - declare_test!{StateTests_RandomTests_st201506101359JS, "StateTests/RandomTests/st201506101359JS"} - declare_test!{StateTests_RandomTests_st201507030359GO, "StateTests/RandomTests/st201507030359GO"} + declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"} + declare_test!{GeneralStateTest_stBlockHashTest, "GeneralStateTests/stBlockHashTest/"} + declare_test!{GeneralStateTest_stBoundsTest, "GeneralStateTests/stBoundsTest/"} + declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"} + declare_test!{skip => [ "createJS_ExampleContract" ], GeneralStateTest_stCallCreateCallCodeTest, "GeneralStateTests/stCallCreateCallCodeTest/"} + declare_test!{GeneralStateTest_stCallDelegateCodesCallCodeHomestead, "GeneralStateTests/stCallDelegateCodesCallCodeHomestead/"} + declare_test!{GeneralStateTest_stCallDelegateCodesHomestead, "GeneralStateTests/stCallDelegateCodesHomestead/"} + declare_test!{GeneralStateTest_stChangedEIP150, "GeneralStateTests/stChangedEIP150/"} + declare_test!{GeneralStateTest_stCodeSizeLimit, "GeneralStateTests/stCodeSizeLimit/"} + declare_test!{GeneralStateTest_stCreateTest, "GeneralStateTests/stCreateTest/"} + declare_test!{GeneralStateTest_stDelegatecallTestHomestead, "GeneralStateTests/stDelegatecallTestHomestead/"} + declare_test!{GeneralStateTest_stEIP150singleCodeGasPrices, "GeneralStateTests/stEIP150singleCodeGasPrices/"} + declare_test!{GeneralStateTest_stEIP150Specific, "GeneralStateTests/stEIP150Specific/"} + declare_test!{GeneralStateTest_stExample, "GeneralStateTests/stExample/"} + declare_test!{GeneralStateTest_stHomesteadSpecific, "GeneralStateTests/stHomesteadSpecific/"} + declare_test!{GeneralStateTest_stInitCodeTest, "GeneralStateTests/stInitCodeTest/"} + declare_test!{GeneralStateTest_stLogTests, "GeneralStateTests/stLogTests/"} + declare_test!{GeneralStateTest_stMemExpandingEIP150Calls, "GeneralStateTests/stMemExpandingEIP150Calls/"} + declare_test!{heavy => GeneralStateTest_stMemoryStressTest, "GeneralStateTests/stMemoryStressTest/"} + declare_test!{GeneralStateTest_stMemoryTest, "GeneralStateTests/stMemoryTest/"} + declare_test!{GeneralStateTest_stNonZeroCallsTest, "GeneralStateTests/stNonZeroCallsTest/"} + declare_test!{GeneralStateTest_stPreCompiledContracts, "GeneralStateTests/stPreCompiledContracts/"} + declare_test!{heavy => GeneralStateTest_stQuadraticComplexityTest, "GeneralStateTests/stQuadraticComplexityTest/"} + declare_test!{GeneralStateTest_stRandom, "GeneralStateTests/stRandom/"} + declare_test!{GeneralStateTest_stRecursiveCreate, "GeneralStateTests/stRecursiveCreate/"} + declare_test!{GeneralStateTest_stRefundTest, "GeneralStateTests/stRefundTest/"} + declare_test!{skip => [ "RevertDepthCreateAddressCollision" ], GeneralStateTest_stRevertTest, "GeneralStateTests/stRevertTest/"} + declare_test!{GeneralStateTest_stSolidityTest, "GeneralStateTests/stSolidityTest/"} + declare_test!{GeneralStateTest_stSpecialTest, "GeneralStateTests/stSpecialTest/"} + declare_test!{GeneralStateTest_stStackTests, "GeneralStateTests/stStackTests/"} + declare_test!{GeneralStateTest_stSystemOperationsTest, "GeneralStateTests/stSystemOperationsTest/"} + declare_test!{GeneralStateTest_stTransactionTest, "GeneralStateTests/stTransactionTest/"} + declare_test!{GeneralStateTest_stTransitionTest, "GeneralStateTests/stTransitionTest/"} + declare_test!{GeneralStateTest_stWalletTest, "GeneralStateTests/stWalletTest/"} + declare_test!{GeneralStateTest_stZeroCallsRevert, "GeneralStateTests/stZeroCallsRevert/"} + declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"} } + diff --git a/ethcore/src/json_tests/test_common.rs b/ethcore/src/json_tests/test_common.rs index fd612b994..f9716d221 100644 --- a/ethcore/src/json_tests/test_common.rs +++ b/ethcore/src/json_tests/test_common.rs @@ -15,21 +15,63 @@ // along with Parity. If not, see . pub use util::*; +use std::fs::{File, read_dir}; +use std::path::Path; +use std::ffi::OsString; + +pub fn run_test_path(p: &Path, skip: &[&'static str], runner: fn (json_data: &[u8]) -> Vec) { + let path = Path::new(p); + let s: HashSet = skip.iter().map(|s| { + let mut os: OsString = s.into(); + os.push(".json"); + os + }).collect(); + if path.is_dir() { + for p in read_dir(path).unwrap().filter_map(|e| { + let e = e.unwrap(); + if s.contains(&e.file_name()) { + None + } else { + Some(e.path()) + }}) { + run_test_path(&p, skip, runner) + } + } else { + let mut path = p.to_path_buf(); + path.set_extension("json"); + run_test_file(&path, runner) + } +} + +pub fn run_test_file(path: &Path, runner: fn (json_data: &[u8]) -> Vec) { + let mut data = Vec::new(); + let mut file = File::open(&path).expect("Error opening test file"); + file.read_to_end(&mut data).expect("Error reading test file"); + let results = runner(&data); + assert!(results.is_empty()); +} macro_rules! test { - ($name: expr) => { - assert!(do_json_test(include_bytes!(concat!("../../res/ethereum/tests/", $name, ".json"))).is_empty()); + ($name: expr, $skip: expr) => { + ::json_tests::test_common::run_test_path(::std::path::Path::new(concat!("res/ethereum/tests/", $name)), &$skip, do_json_test); } } #[macro_export] macro_rules! declare_test { + (skip => $arr: expr, $id: ident, $name: expr) => { + #[test] + #[allow(non_snake_case)] + fn $id() { + test!($name, $arr); + } + }; (ignore => $id: ident, $name: expr) => { #[ignore] #[test] #[allow(non_snake_case)] fn $id() { - test!($name); + test!($name, []); } }; (heavy => $id: ident, $name: expr) => { @@ -37,14 +79,14 @@ macro_rules! declare_test { #[test] #[allow(non_snake_case)] fn $id() { - test!($name); + test!($name, []); } }; ($id: ident, $name: expr) => { #[test] #[allow(non_snake_case)] fn $id() { - test!($name); + test!($name, []); } } } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 2f55fd581..70269b6e4 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -42,7 +42,7 @@ pub enum ChainEra { Frontier, Homestead, Eip150, - Eip161, + _Eip161, TransitionTest, } @@ -359,12 +359,23 @@ pub fn get_temp_state() -> GuardedTempResult> { } } +pub fn get_temp_mem_state() -> State<::state_db::StateDB> { + let journal_db = get_temp_mem_state_db(); + State::new(journal_db, U256::from(0), Default::default()) +} + pub fn get_temp_state_db_in(path: &Path) -> StateDB { let db = new_db(path.to_str().expect("Only valid utf8 paths for tests.")); let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); StateDB::new(journal_db, 5 * 1024 * 1024) } +pub fn get_temp_mem_state_db() -> StateDB { + let db = Arc::new(::util::kvdb::in_memory(::db::NUM_COLUMNS.unwrap_or(0))); + let journal_db = journaldb::new(db, journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); + StateDB::new(journal_db, 5 * 1024 * 1024) +} + pub fn get_temp_state_in(path: &Path) -> State<::state_db::StateDB> { let journal_db = get_temp_state_db_in(path); State::new(journal_db, U256::from(0), Default::default()) diff --git a/json/src/maybe.rs b/json/src/maybe.rs index d80020cf2..16a01dc44 100644 --- a/json/src/maybe.rs +++ b/json/src/maybe.rs @@ -8,7 +8,7 @@ use serde::de::{Error, Visitor}; use serde::de::value::ValueDeserializer; /// Deserializer of empty string values into optionals. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub enum MaybeEmpty { /// Some. Some(T), diff --git a/json/src/state/test.rs b/json/src/state/test.rs index 0ee0bcf17..5cc2b5f4f 100644 --- a/json/src/state/test.rs +++ b/json/src/state/test.rs @@ -14,13 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! State test deserializer. +//! General test deserialization. -use std::collections::BTreeMap; use std::io::Read; -use serde_json; -use serde_json::Error; -use state::State; +use std::collections::BTreeMap; +use uint::Uint; +use bytes::Bytes; +use hash::{Address, H256}; +use state::{Env, AccountState, Transaction}; +use maybe::MaybeEmpty; +use serde_json::{self, Error}; /// State test deserializer. #[derive(Debug, PartialEq, Deserialize)] @@ -41,3 +44,182 @@ impl Test { serde_json::from_reader(reader) } } + +/// State test deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct State { + /// Environment. + pub env: Env, + /// Pre state. + #[serde(rename="pre")] + pub pre_state: AccountState, + /// Post state. + #[serde(rename="post")] + pub post_states: BTreeMap>, + /// Transaction. + pub transaction: MultiTransaction, +} + +/// State test transaction deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct MultiTransaction { + /// Transaction data set. + pub data: Vec, + /// Gas limit set. + #[serde(rename="gasLimit")] + pub gas_limit: Vec, + /// Gas price. + #[serde(rename="gasPrice")] + pub gas_price: Uint, + /// Nonce. + pub nonce: Uint, + /// Secret key. + #[serde(rename="secretKey")] + pub secret: H256, + /// To. + pub to: MaybeEmpty
, + /// Value set. + pub value: Vec, +} + +impl MultiTransaction { + /// Build transaction with given indexes. + pub fn select(&self, indexes: &PostStateIndexes) -> Transaction { + Transaction { + data: self.data[indexes.data as usize].clone(), + gas_limit: self.gas_limit[indexes.gas as usize].clone(), + gas_price: self.gas_price.clone(), + nonce: self.nonce.clone(), + secret: self.secret.clone(), + to: self.to.clone(), + value: self.value[indexes.value as usize].clone(), + } + } +} + +/// State test transaction deserialization. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize)] +pub enum ForkSpec { + EIP150, + EIP158, + Frontier, + Homestead, + Metropolis, +} + +/// State test indexes deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct PostStateIndexes { + /// Index into transaction data set. + pub data: u64, + /// Index into transaction gas limit set. + pub gas: u64, + /// Index into transaction value set. + pub value: u64, +} + +/// State test indexed state result deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct PostStateResult { + /// Post state hash + pub hash: H256, + /// Indexes + pub indexes: PostStateIndexes, +} + +#[cfg(test)] +mod tests { + use serde_json; + use super::{MultiTransaction, State}; + + #[test] + fn multi_transaction_deserialization() { + let s = r#"{ + "data" : [ "" ], + "gasLimit" : [ "0x2dc6c0", "0x222222" ], + "gasPrice" : "0x01", + "nonce" : "0x00", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "1000000000000000000000000000000000000000", + "value" : [ "0x00", "0x01", "0x02" ] + }"#; + let _deserialized: MultiTransaction = serde_json::from_str(s).unwrap(); + } + + #[test] + fn state_deserialization() { + let s = r#"{ + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "0x0100", + "currentGasLimit" : "0x01c9c380", + "currentNumber" : "0x00", + "currentTimestamp" : "0x01", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "post" : { + "EIP150" : [ + { + "hash" : "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f", + "indexes" : { "data" : 0, "gas" : 0, "value" : 0 } + }, + { + "hash" : "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764", + "indexes" : { "data" : 0, "gas" : 0, "value" : 1 } + } + ], + "EIP158" : [ + { + "hash" : "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f", + "indexes" : { "data" : 0, "gas" : 0, "value" : 0 } + }, + { + "hash" : "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764", + "indexes" : { "data" : 0, "gas" : 0, "value" : 1 } + } + ] + }, + "pre" : { + "1000000000000000000000000000000000000000" : { + "balance" : "0x0de0b6b3a7640000", + "code" : "0x6040600060406000600173100000000000000000000000000000000000000162055730f1600055", + "nonce" : "0x00", + "storage" : { + } + }, + "1000000000000000000000000000000000000001" : { + "balance" : "0x0de0b6b3a7640000", + "code" : "0x604060006040600060027310000000000000000000000000000000000000026203d090f1600155", + "nonce" : "0x00", + "storage" : { + } + }, + "1000000000000000000000000000000000000002" : { + "balance" : "0x00", + "code" : "0x600160025533600455346007553060e6553260e8553660ec553860ee553a60f055", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x0de0b6b3a7640000", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + } + }, + "transaction" : { + "data" : [ "" ], + "gasLimit" : [ "285000", "100000", "6000" ], + "gasPrice" : "0x01", + "nonce" : "0x00", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : [ "10", "0" ] + } + }"#; + let _deserialized: State = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} From d99f1e5f1f98b810cead9730c60e47896bb77d8b Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Wed, 12 Apr 2017 11:52:33 +0000 Subject: [PATCH 13/29] [ci skip] js-precompiled 20170412-114838 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7e412349..28c08c8c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1761,7 +1761,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#fb24b1a459fc7f5b3de5fe21060bc17e1e161e5e" +source = "git+https://github.com/paritytech/js-precompiled.git#fef6ae14b9f8ec55332069dc5d309e44e9e56685" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index f20ea0574..f25a82d5b 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.51", + "version": "1.7.52", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From c58fd744ee95d4bed74b138dfa213c0a3d6ef2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 12 Apr 2017 15:04:53 +0200 Subject: [PATCH 14/29] Fix removal of hash-mismatched files. (#5440) --- hash-fetch/src/client.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index cffc10e63..40682a89c 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -92,6 +92,7 @@ pub struct Client { contract: URLHintContract, fetch: F, remote: Remote, + random_path: Arc PathBuf + Sync + Send>, } impl Client { @@ -109,6 +110,7 @@ impl Client { contract: URLHintContract::new(contract), fetch: fetch, remote: remote, + random_path: Arc::new(random_temp_path), } } } @@ -131,6 +133,7 @@ impl HashFetch for Client { match url { Err(err) => on_done(Err(err)), Ok(url) => { + let random_path = self.random_path.clone(); let future = self.fetch.fetch(&url).then(move |result| { fn validate_hash(path: PathBuf, hash: H256, result: Result) -> Result { let response = result?; @@ -155,12 +158,12 @@ impl HashFetch for Client { } debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash); - let path = random_temp_path(); + let path = random_path(); let res = validate_hash(path.clone(), hash, result); if let Err(ref err) = res { trace!(target: "fetch", "Error: {:?}", err); // Remove temporary file in case of error - let _ = fs::remove_dir_all(&path); + let _ = fs::remove_file(&path); } on_done(res); @@ -192,7 +195,7 @@ mod tests { use fetch::{self, Fetch}; use parity_reactor::Remote; use urlhint::tests::{FakeRegistrar, URLHINT}; - use super::{Error, Client, HashFetch}; + use super::{Error, Client, HashFetch, random_temp_path}; #[derive(Clone)] @@ -262,12 +265,16 @@ mod tests { let result = rx.recv().unwrap(); assert_eq!(result.unwrap_err(), Error::InvalidStatus); } + #[test] fn should_return_hash_mismatch() { // given let registrar = Arc::new(registrar()); let fetch = FakeFetch { return_success: true }; - let client = Client::with_fetch(registrar.clone(), fetch, Remote::new_sync()); + let mut client = Client::with_fetch(registrar.clone(), fetch, Remote::new_sync()); + let path = random_temp_path(); + let path2 = path.clone(); + client.random_path = Arc::new(move || path2.clone()); // when let (tx, rx) = mpsc::channel(); @@ -279,6 +286,7 @@ mod tests { let result = rx.recv().unwrap(); let hash = "0x06b0a4f426f6713234b2d4b2468640bc4e0bb72657a920ad24c5087153c593c8".into(); assert_eq!(result.unwrap_err(), Error::HashMismatch { expected: 2.into(), got: hash }); + assert!(!path.exists(), "Temporary file should be removed."); } #[test] From 1e6674f804437f1a53fd6e054c50e09269dc1817 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Thu, 13 Apr 2017 08:37:35 +0000 Subject: [PATCH 15/29] [ci skip] js-precompiled 20170413-083353 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28c08c8c8..d8561cd11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1761,7 +1761,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#fef6ae14b9f8ec55332069dc5d309e44e9e56685" +source = "git+https://github.com/paritytech/js-precompiled.git#fb346e5f2925d1b2d533eb986bd2cefb962c7a88" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index f25a82d5b..4f4b33ab7 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.52", + "version": "1.7.53", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From 314af4cdae217355cd52d70fc3ea81b77ded498b Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 6 Apr 2017 19:26:17 +0200 Subject: [PATCH 16/29] Use in-memory database in tests --- ethcore/src/block.rs | 15 ++-- ethcore/src/blockchain/blockchain.rs | 12 +-- ethcore/src/client/client.rs | 2 +- ethcore/src/engines/authority_round.rs | 4 +- ethcore/src/engines/basic_authority.rs | 3 +- ethcore/src/engines/instant_seal.rs | 3 +- ethcore/src/engines/tendermint/mod.rs | 4 +- ethcore/src/ethereum/ethash.rs | 6 +- ethcore/src/ethereum/mod.rs | 3 +- ethcore/src/executive.rs | 39 +++----- ethcore/src/externalities.rs | 15 ++-- ethcore/src/json_tests/executive.rs | 3 +- ethcore/src/json_tests/state.rs | 2 +- ethcore/src/miner/miner.rs | 11 ++- ethcore/src/spec/spec.rs | 3 +- ethcore/src/state/mod.rs | 97 +++++++------------- ethcore/src/state_db.rs | 3 +- ethcore/src/tests/client.rs | 63 +++++-------- ethcore/src/tests/helpers.rs | 118 ++++++------------------- 19 files changed, 130 insertions(+), 276 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 12e77d41b..46a0db733 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -667,8 +667,7 @@ mod tests { use spec::*; let spec = Spec::new_test(); let genesis_header = spec.genesis_header(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); @@ -682,16 +681,14 @@ mod tests { let engine = &*spec.engine; let genesis_header = spec.genesis_header(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() .close_and_lock().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -708,8 +705,7 @@ mod tests { let engine = &*spec.engine; let genesis_header = spec.genesis_header(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle1_header = Header::new(); @@ -723,8 +719,7 @@ mod tests { let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); let bytes = e.rlp_bytes(); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8986dc6b8..39c1039ca 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1791,15 +1791,13 @@ mod tests { #[test] fn can_contain_arbitrary_block_sequence() { - let bc_result = generate_dummy_blockchain(50); - let bc = bc_result.reference(); + let bc = generate_dummy_blockchain(50); assert_eq!(bc.best_block_number(), 49); } #[test] fn can_collect_garbage() { - let bc_result = generate_dummy_blockchain(3000); - let bc = bc_result.reference(); + let bc = generate_dummy_blockchain(3000); assert_eq!(bc.best_block_number(), 2999); let best_hash = bc.best_block_hash(); @@ -1818,15 +1816,13 @@ mod tests { #[test] fn can_contain_arbitrary_block_sequence_with_extra() { - let bc_result = generate_dummy_blockchain_with_extra(25); - let bc = bc_result.reference(); + let bc = generate_dummy_blockchain_with_extra(25); assert_eq!(bc.best_block_number(), 24); } #[test] fn can_contain_only_genesis_block() { - let bc_result = generate_dummy_empty_blockchain(); - let bc = bc_result.reference(); + let bc = generate_dummy_empty_blockchain(); assert_eq!(bc.best_block_number(), 0); } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 4bd29d100..2ad4fa8d6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1717,7 +1717,7 @@ mod tests { // Separate thread uncommited transaction let go = Arc::new(AtomicBool::new(false)); let go_thread = go.clone(); - let another_client = client.reference().clone(); + let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new()); diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index e6cbdb531..2e8e3932c 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -454,8 +454,8 @@ mod tests { let spec = Spec::new_test_round(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); - let db1 = spec.ensure_db_good(get_temp_state_db().take(), &Default::default()).unwrap(); - let db2 = spec.ensure_db_good(get_temp_state_db().take(), &Default::default()).unwrap(); + let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); + let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b1 = b1.close_and_lock(); diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index e5a53d4e9..19867a648 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -252,8 +252,7 @@ mod tests { let engine = &*spec.engine; engine.set_signer(Arc::new(tap), addr, "".into()); let genesis_header = spec.genesis_header(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 45bede9f4..88672c6f4 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -82,8 +82,7 @@ mod tests { fn instant_can_seal() { let spec = Spec::new_instant(); let engine = &*spec.engine; - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap(); diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 8c8094117..cb284d3c4 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -676,8 +676,8 @@ mod tests { } fn propose_default(spec: &Spec, proposer: Address) -> (ClosedBlock, Vec) { - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = get_temp_state_db(); + let db = spec.ensure_db_good(db, &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![]).unwrap(); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 5bc31c5d9..88655fa86 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -524,8 +524,7 @@ mod tests { let spec = new_morden(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close(); @@ -537,8 +536,7 @@ mod tests { let spec = new_morden(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle = Header::new(); diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index ce8b84b31..b54401572 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -94,8 +94,7 @@ mod tests { let spec = new_morden(); let engine = &spec.engine; let genesis_header = spec.genesis_header(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap(); assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()).unwrap(), 1u64.into()); assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()).unwrap(), 1u64.into()); diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 4183a5005..5e0ee5662 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -554,8 +554,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new("3331600055".from_hex().unwrap())); params.value = ActionValue::Transfer(U256::from(0x7)); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(0); @@ -613,8 +612,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from(100)); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(0); @@ -672,8 +670,7 @@ mod tests { params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from(100)); params.call_type = CallType::Call; - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(5); @@ -783,8 +780,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(100.into()); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(5); @@ -871,8 +867,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from(100)); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(0); @@ -923,8 +918,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from(100)); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(1024); @@ -981,8 +975,7 @@ mod tests { params.code = Some(Arc::new(code_a.clone())); params.value = ActionValue::Transfer(U256::from(100_000)); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.init_code(&address_a, code_a.clone()).unwrap(); state.init_code(&address_b, code_b.clone()).unwrap(); state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty).unwrap(); @@ -1029,8 +1022,7 @@ mod tests { params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(Arc::new(code.clone())); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.init_code(&address, code).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(0); @@ -1062,8 +1054,7 @@ mod tests { let sender = t.sender(); let contract = contract_address(&sender, &U256::zero()); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty).unwrap(); let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); @@ -1100,8 +1091,7 @@ mod tests { }.sign(keypair.secret(), None); let sender = t.sender(); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap(); let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); @@ -1133,8 +1123,7 @@ mod tests { }.sign(keypair.secret(), None); let sender = t.sender(); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap(); let mut info = EnvInfo::default(); info.gas_used = U256::from(20_000); @@ -1168,8 +1157,7 @@ mod tests { }.sign(keypair.secret(), None); let sender = t.sender(); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty).unwrap(); let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); @@ -1203,8 +1191,7 @@ mod tests { params.gas = U256::from(0x0186a0); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap()); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let engine = TestEngine::new(0); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 893ba03be..8591f15fd 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -346,7 +346,6 @@ mod tests { use evm::Ext; use state::{State, Substate}; use tests::helpers::*; - use devtools::GuardedTempResult; use super::*; use trace::{NoopTracer, NoopVMTracer}; use types::executed::CallType; @@ -373,7 +372,7 @@ mod tests { } struct TestSetup { - state: GuardedTempResult>, + state: State<::state_db::StateDB>, engine: Arc, sub_state: Substate, env_info: EnvInfo @@ -399,7 +398,7 @@ mod tests { #[test] fn can_be_created() { let mut setup = TestSetup::new(); - let state = setup.state.reference_mut(); + let state = &mut setup.state; let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; @@ -412,7 +411,7 @@ mod tests { #[test] fn can_return_block_hash_no_env() { let mut setup = TestSetup::new(); - let state = setup.state.reference_mut(); + let state = &mut setup.state; let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; @@ -437,7 +436,7 @@ mod tests { last_hashes.push(test_hash.clone()); env_info.last_hashes = Arc::new(last_hashes); } - let state = setup.state.reference_mut(); + let state = &mut setup.state; let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; @@ -453,7 +452,7 @@ mod tests { #[should_panic] fn can_call_fail_empty() { let mut setup = TestSetup::new(); - let state = setup.state.reference_mut(); + let state = &mut setup.state; let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; @@ -481,7 +480,7 @@ mod tests { let log_topics = vec![H256::from("af0fa234a6af46afa23faf23bcbc1c1cb4bcb7bcbe7e7e7ee3ee2edddddddddd")]; let mut setup = TestSetup::new(); - let state = setup.state.reference_mut(); + let state = &mut setup.state; let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; @@ -499,7 +498,7 @@ mod tests { let refund_account = &Address::new(); let mut setup = TestSetup::new(); - let state = setup.state.reference_mut(); + let state = &mut setup.state; let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 844fa08f5..9526e5ec2 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -215,8 +215,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { } let out_of_gas = vm.out_of_gas(); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.populate_from(From::from(vm.pre_state.clone())); let info = From::from(vm.env); let engine = TestEngine::new(1); diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index e4b9390db..d0b18d99c 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -56,7 +56,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { let post_root: H256 = state.hash.into(); let transaction = multitransaction.select(&state.indexes).into(); - let mut state = get_temp_mem_state(); + let mut state = get_temp_state(); state.populate_from(pre.clone()); state.commit().expect(&format!("State test {} failed due to internal error.", name)); let _res = state.apply(&env, &**engine, &transaction, false); diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index ac1695b52..0347e984f 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1413,19 +1413,18 @@ mod tests { fn internal_seals_without_work() { let miner = Miner::with_spec(&Spec::new_instant()); - let c = generate_dummy_client(2); - let client = c.reference().as_ref(); + let client = generate_dummy_client(2); - assert_eq!(miner.import_external_transactions(client, vec![transaction().into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); + assert_eq!(miner.import_external_transactions(&*client, vec![transaction().into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); - miner.update_sealing(client); + miner.update_sealing(&*client); client.flush_queue(); assert!(miner.pending_block().is_none()); assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber); - assert_eq!(miner.import_own_transaction(client, PendingTransaction::new(transaction().into(), None)).unwrap(), TransactionImportResult::Current); + assert_eq!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction().into(), None)).unwrap(), TransactionImportResult::Current); - miner.update_sealing(client); + miner.update_sealing(&*client); client.flush_queue(); assert!(miner.pending_block().is_none()); assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber); diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 9051bcbcf..35f1ca983 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -392,8 +392,7 @@ mod tests { #[test] fn genesis_constructor() { let spec = Spec::new_test_constructor(); - let mut db_result = get_temp_state_db(); - let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let state = State::from_existing(db.boxed_clone(), spec.state_root(), spec.engine.account_start_nonce(), Default::default()).unwrap(); let expected = H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); assert_eq!(state.storage_at(&Address::from_str("0000000000000000000000000000000000000005").unwrap(), &H256::zero()).unwrap(), expected); diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index b1594dd9b..12d7718cc 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -939,7 +939,6 @@ mod tests { use ethkey::Secret; use util::{U256, H256, Address, Hashable}; use tests::helpers::*; - use devtools::*; use env_info::EnvInfo; use spec::*; use transaction::*; @@ -955,8 +954,7 @@ mod tests { fn should_apply_create_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -998,9 +996,8 @@ mod tests { let a = Address::zero(); - let temp = RandomTempPath::new(); let mut state = { - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); assert_eq!(state.exists(&a).unwrap(), false); state.inc_nonce(&a).unwrap(); state.commit().unwrap(); @@ -1015,8 +1012,7 @@ mod tests { fn should_trace_failed_create_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1052,8 +1048,7 @@ mod tests { fn should_trace_call_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1095,8 +1090,7 @@ mod tests { fn should_trace_basic_call_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1137,8 +1131,7 @@ mod tests { fn should_trace_call_transaction_to_builtin() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1179,8 +1172,7 @@ mod tests { fn should_not_trace_subcall_transaction_to_builtin() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1222,8 +1214,7 @@ mod tests { fn should_not_trace_callcode() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1281,8 +1272,7 @@ mod tests { fn should_not_trace_delegatecall() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1343,8 +1333,7 @@ mod tests { fn should_trace_failed_call_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1383,8 +1372,7 @@ mod tests { fn should_trace_call_with_subcall_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1443,8 +1431,7 @@ mod tests { fn should_trace_call_with_basic_subcall_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1498,8 +1485,7 @@ mod tests { fn should_not_trace_call_with_invalid_basic_subcall_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1541,8 +1527,7 @@ mod tests { fn should_trace_failed_subcall_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1597,8 +1582,7 @@ mod tests { fn should_trace_call_with_subcall_with_subcall_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1672,8 +1656,7 @@ mod tests { fn should_trace_failed_subcall_with_subcall_transaction() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1745,8 +1728,7 @@ mod tests { fn should_trace_suicide() { init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); @@ -1797,9 +1779,8 @@ mod tests { #[test] fn code_from_database() { let a = Address::zero(); - let temp = RandomTempPath::new(); let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}).unwrap(); state.init_code(&a, vec![1, 2, 3]).unwrap(); assert_eq!(state.code(&a).unwrap(), Some(Arc::new([1u8, 2, 3].to_vec()))); @@ -1815,9 +1796,8 @@ mod tests { #[test] fn storage_at_from_database() { let a = Address::zero(); - let temp = RandomTempPath::new(); let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64))).unwrap(); state.commit().unwrap(); state.drop() @@ -1830,9 +1810,8 @@ mod tests { #[test] fn get_from_database() { let a = Address::zero(); - let temp = RandomTempPath::new(); let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); state.inc_nonce(&a).unwrap(); state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty).unwrap(); state.commit().unwrap(); @@ -1848,8 +1827,7 @@ mod tests { #[test] fn remove() { let a = Address::zero(); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); assert_eq!(state.exists(&a).unwrap(), false); assert_eq!(state.exists_and_not_null(&a).unwrap(), false); state.inc_nonce(&a).unwrap(); @@ -1865,8 +1843,7 @@ mod tests { #[test] fn empty_account_is_not_created() { let a = Address::zero(); - let path = RandomTempPath::new(); - let db = get_temp_state_db_in(path.as_path()); + let db = get_temp_state_db(); let (root, db) = { let mut state = State::new(db, U256::from(0), Default::default()); state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty).unwrap(); // create an empty account @@ -1881,8 +1858,7 @@ mod tests { #[test] fn empty_account_exists_when_creation_forced() { let a = Address::zero(); - let path = RandomTempPath::new(); - let db = get_temp_state_db_in(path.as_path()); + let db = get_temp_state_db(); let (root, db) = { let mut state = State::new(db, U256::from(0), Default::default()); state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate).unwrap(); // create an empty account @@ -1897,9 +1873,8 @@ mod tests { #[test] fn remove_from_database() { let a = Address::zero(); - let temp = RandomTempPath::new(); let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); + let mut state = get_temp_state(); state.inc_nonce(&a).unwrap(); state.commit().unwrap(); assert_eq!(state.exists(&a).unwrap(), true); @@ -1925,8 +1900,7 @@ mod tests { #[test] fn alter_balance() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); let a = Address::zero(); let b = 1u64.into(); state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty).unwrap(); @@ -1947,8 +1921,7 @@ mod tests { #[test] fn alter_nonce() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); let a = Address::zero(); state.inc_nonce(&a).unwrap(); assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64)); @@ -1964,8 +1937,7 @@ mod tests { #[test] fn balance_nonce() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); let a = Address::zero(); assert_eq!(state.balance(&a).unwrap(), U256::from(0u64)); assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64)); @@ -1976,8 +1948,7 @@ mod tests { #[test] fn ensure_cached() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); let a = Address::zero(); state.require(&a, false).unwrap(); state.commit().unwrap(); @@ -1986,8 +1957,7 @@ mod tests { #[test] fn checkpoint_basic() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); let a = Address::zero(); state.checkpoint(); state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty).unwrap(); @@ -2003,8 +1973,7 @@ mod tests { #[test] fn checkpoint_nested() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); let a = Address::zero(); state.checkpoint(); state.checkpoint(); @@ -2018,16 +1987,14 @@ mod tests { #[test] fn create_empty() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); + let mut state = get_temp_state(); state.commit().unwrap(); assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); } #[test] fn should_not_panic_on_state_diff_with_storage() { - let state = get_temp_state(); - let mut state = state.reference().clone(); + let mut state = get_temp_state(); let a: Address = 0xa.into(); state.init_code(&a, b"abcdefg".to_vec()).unwrap();; diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 2831d2f9b..6bf8bbd8e 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -463,8 +463,7 @@ mod tests { fn state_db_smoke() { init_log(); - let mut state_db_result = get_temp_state_db(); - let state_db = state_db_result.take(); + let state_db = get_temp_state_db(); let root_parent = H256::random(); let address = Address::random(); let h0 = H256::random(); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index e61edd478..6f0d7bc26 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -72,8 +72,7 @@ fn should_return_registrar() { #[test] fn returns_state_root_basic() { - let client_result = generate_dummy_client(6); - let client = client_result.reference(); + let client = generate_dummy_client(6); let test_spec = get_test_spec(); let genesis_header = test_spec.genesis_header(); @@ -125,8 +124,7 @@ fn query_none_block() { #[test] fn query_bad_block() { - let client_result = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]); - let client = client_result.reference(); + let client = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]); let bad_block: Option<_> = client.block_header(BlockId::Number(1)); assert!(bad_block.is_none()); @@ -135,8 +133,7 @@ fn query_bad_block() { #[test] fn returns_chain_info() { let dummy_block = get_good_dummy_block(); - let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]); - let client = client_result.reference(); + let client = get_test_client_with_blocks(vec![dummy_block.clone()]); let block = BlockView::new(&dummy_block); let info = client.chain_info(); assert_eq!(info.best_block_hash, block.header().hash()); @@ -145,8 +142,7 @@ fn returns_chain_info() { #[test] fn returns_logs() { let dummy_block = get_good_dummy_block(); - let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]); - let client = client_result.reference(); + let client = get_test_client_with_blocks(vec![dummy_block.clone()]); let logs = client.logs(Filter { from_block: BlockId::Earliest, to_block: BlockId::Latest, @@ -160,8 +156,7 @@ fn returns_logs() { #[test] fn returns_logs_with_limit() { let dummy_block = get_good_dummy_block(); - let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]); - let client = client_result.reference(); + let client = get_test_client_with_blocks(vec![dummy_block.clone()]); let logs = client.logs(Filter { from_block: BlockId::Earliest, to_block: BlockId::Latest, @@ -175,8 +170,7 @@ fn returns_logs_with_limit() { #[test] fn returns_block_body() { let dummy_block = get_good_dummy_block(); - let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]); - let client = client_result.reference(); + let client = get_test_client_with_blocks(vec![dummy_block.clone()]); let block = BlockView::new(&dummy_block); let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap(); let body = body.rlp(); @@ -187,8 +181,7 @@ fn returns_block_body() { #[test] fn imports_block_sequence() { - let client_result = generate_dummy_client(6); - let client = client_result.reference(); + let client = generate_dummy_client(6); let block = client.block_header(BlockId::Number(5)).unwrap(); assert!(!block.into_inner().is_empty()); @@ -196,8 +189,7 @@ fn imports_block_sequence() { #[test] fn can_collect_garbage() { - let client_result = generate_dummy_client(100); - let client = client_result.reference(); + let client = generate_dummy_client(100); client.tick(); assert!(client.blockchain_cache_info().blocks < 100 * 1024); } @@ -205,19 +197,16 @@ fn can_collect_garbage() { #[test] fn can_generate_gas_price_median() { - let client_result = generate_dummy_client_with_data(3, 1, slice_into![1, 2, 3]); - let client = client_result.reference(); + let client = generate_dummy_client_with_data(3, 1, slice_into![1, 2, 3]); assert_eq!(Some(&U256::from(2)), client.gas_price_corpus(3).median()); - let client_result = generate_dummy_client_with_data(4, 1, slice_into![1, 4, 3, 2]); - let client = client_result.reference(); + let client = generate_dummy_client_with_data(4, 1, slice_into![1, 4, 3, 2]); assert_eq!(Some(&U256::from(3)), client.gas_price_corpus(3).median()); } #[test] fn can_generate_gas_price_histogram() { - let client_result = generate_dummy_client_with_data(20, 1, slice_into![6354,8593,6065,4842,7845,7002,689,4958,4250,6098,5804,4320,643,8895,2296,8589,7145,2000,2512,1408]); - let client = client_result.reference(); + let client = generate_dummy_client_with_data(20, 1, slice_into![6354,8593,6065,4842,7845,7002,689,4958,4250,6098,5804,4320,643,8895,2296,8589,7145,2000,2512,1408]); let hist = client.gas_price_corpus(20).histogram(5).unwrap(); let correct_hist = ::stats::Histogram { bucket_bounds: vec_into![643, 2294, 3945, 5596, 7247, 8898], counts: vec![4,2,4,6,4] }; @@ -226,32 +215,29 @@ fn can_generate_gas_price_histogram() { #[test] fn empty_gas_price_histogram() { - let client_result = generate_dummy_client_with_data(20, 0, slice_into![]); - let client = client_result.reference(); + let client = generate_dummy_client_with_data(20, 0, slice_into![]); assert!(client.gas_price_corpus(20).histogram(5).is_none()); } #[test] fn corpus_is_sorted() { - let client_result = generate_dummy_client_with_data(2, 1, slice_into![U256::from_str("11426908979").unwrap(), U256::from_str("50426908979").unwrap()]); - let client = client_result.reference(); + let client = generate_dummy_client_with_data(2, 1, slice_into![U256::from_str("11426908979").unwrap(), U256::from_str("50426908979").unwrap()]); let corpus = client.gas_price_corpus(20); assert!(corpus[0] < corpus[1]); } #[test] fn can_handle_long_fork() { - let client_result = generate_dummy_client(1200); - let client = client_result.reference(); + let client = generate_dummy_client(1200); for _ in 0..20 { client.import_verified_blocks(); } assert_eq!(1200, client.chain_info().best_block_number); - push_blocks_to_client(client, 45, 1201, 800); - push_blocks_to_client(client, 49, 1201, 800); - push_blocks_to_client(client, 53, 1201, 600); + push_blocks_to_client(&client, 45, 1201, 800); + push_blocks_to_client(&client, 49, 1201, 800); + push_blocks_to_client(&client, 53, 1201, 600); for _ in 0..400 { client.import_verified_blocks(); @@ -262,8 +248,7 @@ fn can_handle_long_fork() { #[test] fn can_mine() { let dummy_blocks = get_good_dummy_block_seq(2); - let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); - let client = client_result.reference(); + let client = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).close(); @@ -329,14 +314,13 @@ fn does_not_propagate_delayed_transactions() { value: 0.into(), data: Vec::new(), }.sign(secret, None), None); - let client_result = generate_dummy_client(1); - let client = client_result.reference(); + let client = generate_dummy_client(1); - client.miner().import_own_transaction(&**client, tx0).unwrap(); - client.miner().import_own_transaction(&**client, tx1).unwrap(); + client.miner().import_own_transaction(&*client, tx0).unwrap(); + client.miner().import_own_transaction(&*client, tx1).unwrap(); assert_eq!(0, client.ready_transactions().len()); assert_eq!(2, client.miner().pending_transactions().len()); - push_blocks_to_client(client, 53, 2, 2); + push_blocks_to_client(&client, 53, 2, 2); client.flush_queue(); assert_eq!(2, client.ready_transactions().len()); assert_eq!(2, client.miner().pending_transactions().len()); @@ -346,8 +330,7 @@ fn does_not_propagate_delayed_transactions() { fn transaction_proof() { use ::client::ProvingBlockChainClient; - let client_result = generate_dummy_client(0); - let client = client_result.reference(); + let client = generate_dummy_client(0); let address = Address::random(); let test_spec = Spec::new_test(); for _ in 0..20 { diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 70269b6e4..1391c37f4 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -30,7 +30,6 @@ use engines::Engine; use env_info::EnvInfo; use ethereum; use ethereum::ethash::EthashParams; -use devtools::*; use miner::Miner; use header::Header; use transaction::{Action, Transaction, SignedTransaction}; @@ -133,28 +132,26 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[SignedTransa rlp.out() } -pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { +pub fn generate_dummy_client(block_number: u32) -> Arc { generate_dummy_client_with_spec_and_data(Spec::new_test, block_number, 0, &[]) } -pub fn generate_dummy_client_with_data(block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult> { +pub fn generate_dummy_client_with_data(block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> Arc { generate_dummy_client_with_spec_and_data(Spec::new_null, block_number, txs_per_block, tx_gas_prices) } -pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult> where F: Fn()->Spec { +pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> Arc where F: Fn()->Spec { generate_dummy_client_with_spec_accounts_and_data(get_test_spec, None, block_number, txs_per_block, tx_gas_prices) } -pub fn generate_dummy_client_with_spec_and_accounts(get_test_spec: F, accounts: Option>) -> GuardedTempResult> where F: Fn()->Spec { +pub fn generate_dummy_client_with_spec_and_accounts(get_test_spec: F, accounts: Option>) -> Arc where F: Fn()->Spec { generate_dummy_client_with_spec_accounts_and_data(get_test_spec, accounts, 0, 0, &[]) } -pub fn generate_dummy_client_with_spec_accounts_and_data(get_test_spec: F, accounts: Option>, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult> where F: Fn()->Spec { - let dir = RandomTempPath::new(); +pub fn generate_dummy_client_with_spec_accounts_and_data(get_test_spec: F, accounts: Option>, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> Arc where F: Fn()->Spec { let test_spec = get_test_spec(); - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Arc::new(Database::open(&db_config, dir.as_path().to_str().unwrap()).unwrap()); + let client_db = new_db(); let client = Client::new( ClientConfig::default(), @@ -165,8 +162,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(get_test_spec: F, ac ).unwrap(); let test_engine = &*test_spec.engine; - let mut db_result = get_temp_state_db(); - let mut db = test_spec.ensure_db_good(db_result.take(), &Default::default()).unwrap(); + let mut db = test_spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let genesis_header = test_spec.genesis_header(); let mut rolling_timestamp = 40; @@ -220,11 +216,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(get_test_spec: F, ac } client.flush_queue(); client.import_verified_blocks(); - - GuardedTempResult::> { - _temp: dir, - result: Some(client) - } + client } pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting_number: usize, block_number: usize) { @@ -256,11 +248,9 @@ pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting } } -pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { - let dir = RandomTempPath::new(); +pub fn get_test_client_with_blocks(blocks: Vec) -> Arc { let test_spec = get_test_spec(); - let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); - let client_db = Arc::new(Database::open(&db_config, dir.as_path().to_str().unwrap()).unwrap()); + let client_db = new_db(); let client = Client::new( ClientConfig::default(), @@ -277,23 +267,15 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { - _temp: dir, - result: Some(client) - } + client } -fn new_db(path: &str) -> Arc { - Arc::new( - Database::open(&DatabaseConfig::with_columns(::db::NUM_COLUMNS), path) - .expect("Opening database for tests should always work.") - ) +fn new_db() -> Arc { + Arc::new(::util::kvdb::in_memory(::db::NUM_COLUMNS.unwrap_or(0))) } -pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult { - let temp = RandomTempPath::new(); - let db = new_db(temp.as_str()); +pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { + let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); let mut batch = db.transaction(); @@ -302,16 +284,11 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult { - _temp: temp, - result: Some(bc) - } + bc } -pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempResult { - let temp = RandomTempPath::new(); - let db = new_db(temp.as_str()); +pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { + let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); @@ -321,69 +298,29 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes bc.commit(); } db.write(batch).unwrap(); - - GuardedTempResult:: { - _temp: temp, - result: Some(bc) - } + bc } -pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { - let temp = RandomTempPath::new(); - let db = new_db(temp.as_str()); +pub fn generate_dummy_empty_blockchain() -> BlockChain { + let db = new_db(); let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); - - GuardedTempResult:: { - _temp: temp, - result: Some(bc) - } + bc } -pub fn get_temp_state_db() -> GuardedTempResult { - let temp = RandomTempPath::new(); - let journal_db = get_temp_state_db_in(temp.as_path()); - - GuardedTempResult { - _temp: temp, - result: Some(journal_db) - } -} - -pub fn get_temp_state() -> GuardedTempResult> { - let temp = RandomTempPath::new(); - let journal_db = get_temp_state_db_in(temp.as_path()); - - GuardedTempResult { - _temp: temp, - result: Some(State::new(journal_db, U256::from(0), Default::default())), - } -} - -pub fn get_temp_mem_state() -> State<::state_db::StateDB> { - let journal_db = get_temp_mem_state_db(); +pub fn get_temp_state() -> State<::state_db::StateDB> { + let journal_db = get_temp_state_db(); State::new(journal_db, U256::from(0), Default::default()) } -pub fn get_temp_state_db_in(path: &Path) -> StateDB { - let db = new_db(path.to_str().expect("Only valid utf8 paths for tests.")); - let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); - StateDB::new(journal_db, 5 * 1024 * 1024) -} - -pub fn get_temp_mem_state_db() -> StateDB { - let db = Arc::new(::util::kvdb::in_memory(::db::NUM_COLUMNS.unwrap_or(0))); +pub fn get_temp_state_db() -> StateDB { + let db = new_db(); let journal_db = journaldb::new(db, journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); StateDB::new(journal_db, 5 * 1024 * 1024) } -pub fn get_temp_state_in(path: &Path) -> State<::state_db::StateDB> { - let journal_db = get_temp_state_db_in(path); - State::new(journal_db, U256::from(0), Default::default()) -} - pub fn get_good_dummy_block_seq(count: usize) -> Vec { let test_spec = get_test_spec(); - get_good_dummy_block_fork_seq(1, count, &test_spec.genesis_header().hash()) + get_good_dummy_block_fork_seq(1, count, &test_spec.genesis_header().hash()) } pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_hash: &H256) -> Vec { @@ -405,7 +342,6 @@ pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_h rolling_timestamp = rolling_timestamp + 10; r.push(create_test_block(&block_header)); - } r } From 1df30ee83e20a39baa3b416518f3b01f6c56e8ff Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 13 Apr 2017 15:26:07 +0300 Subject: [PATCH 17/29] added missing docs (#5452) --- ethstore/src/account/crypto.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethstore/src/account/crypto.rs b/ethstore/src/account/crypto.rs index 8c4825a22..343e44cb4 100755 --- a/ethstore/src/account/crypto.rs +++ b/ethstore/src/account/crypto.rs @@ -73,10 +73,12 @@ impl From for String { } impl Crypto { + /// Encrypt account secret pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self { Crypto::with_plain(&*secret, password, iterations) } + /// Encrypt custom plain data pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Self { let salt: [u8; 32] = Random::random(); let iv: [u8; 16] = Random::random(); @@ -113,6 +115,7 @@ impl Crypto { } } + /// Try to decrypt and convert result to account secret pub fn secret(&self, password: &str) -> Result { if self.ciphertext.len() > 32 { return Err(Error::InvalidSecret); @@ -122,6 +125,7 @@ impl Crypto { Ok(Secret::from_slice(&secret)?) } + /// Try to decrypt and return result as is pub fn decrypt(&self, password: &str) -> Result, Error> { let expected_len = self.ciphertext.len(); self.do_decrypt(password, expected_len) From ea09aa584d0f2a47105cf15875e7ec72097ea557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 13 Apr 2017 16:32:07 +0200 Subject: [PATCH 18/29] WebSockets RPC server (#5425) * Basic WS server. * CLI for WS server. * Bump jsonrpc * Fixing test. --- .gitlab-ci.yml | 2 +- Cargo.lock | 139 ++++++++++++++++++++------------- Cargo.toml | 10 +-- dapps/src/rpc.rs | 2 +- parity/cli/config.full.toml | 8 ++ parity/cli/config.toml | 3 + parity/cli/mod.rs | 43 +++++++++- parity/cli/usage.txt | 23 +++++- parity/configuration.rs | 38 ++++++++- parity/dapps.rs | 2 +- parity/informant.rs | 4 +- parity/main.rs | 8 +- parity/rpc.rs | 123 +++++++++++++++++++++++------ parity/rpc_apis.rs | 12 +-- parity/run.rs | 9 ++- parity/signer.rs | 12 +-- rpc/Cargo.toml | 5 +- rpc/rpctest/Cargo.toml | 4 +- rpc/rpctest/src/main.rs | 10 +-- rpc/src/lib.rs | 29 ++++++- rpc/src/v1/types/provenance.rs | 7 ++ rpc_cli/Cargo.toml | 2 +- rpc_cli/src/lib.rs | 8 +- rpc_client/Cargo.toml | 2 +- rpc_client/src/lib.rs | 12 +-- scripts/targets.sh | 2 +- signer/Cargo.toml | 2 +- signer/src/lib.rs | 8 +- 28 files changed, 388 insertions(+), 141 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5d90c5d4e..1c2ad13d6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -541,7 +541,7 @@ test-windows: - git submodule update --init --recursive script: - set RUST_BACKTRACE=1 - - echo cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p ethcore-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release + - echo cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p parity-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release tags: - rust-windows allow_failure: true diff --git a/Cargo.lock b/Cargo.lock index d8561cd11..8208f583e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,6 @@ dependencies = [ "ethcore-ipc-tests 0.1.0", "ethcore-light 1.7.0", "ethcore-logger 1.7.0", - "ethcore-rpc 1.7.0", "ethcore-secretstore 1.0.0", "ethcore-signer 1.7.0", "ethcore-stratum 1.7.0", @@ -38,6 +37,7 @@ dependencies = [ "parity-ipfs-api 1.7.0", "parity-local-store 0.1.0", "parity-reactor 0.1.0", + "parity-rpc 1.7.0", "parity-rpc-client 1.4.0", "parity-updater 1.7.0", "path 0.1.0", @@ -592,49 +592,6 @@ dependencies = [ "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethcore-rpc" -version = "1.7.0" -dependencies = [ - "cid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 1.7.0", - "ethcore 1.7.0", - "ethcore-devtools 1.7.0", - "ethcore-io 1.7.0", - "ethcore-ipc 1.7.0", - "ethcore-light 1.7.0", - "ethcore-logger 1.7.0", - "ethcore-util 1.7.0", - "ethcrypto 0.1.0", - "ethjson 0.1.0", - "ethkey 0.2.0", - "ethstore 0.1.0", - "ethsync 1.7.0", - "fetch 0.1.0", - "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", - "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", - "jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", - "jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", - "jsonrpc-minihttp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "multihash 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-reactor 0.1.0", - "parity-updater 1.7.0", - "rlp 0.1.0", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", - "stats 0.1.0", - "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ethcore-secretstore" version = "1.0.0" @@ -674,12 +631,12 @@ dependencies = [ "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-devtools 1.7.0", "ethcore-io 1.7.0", - "ethcore-rpc 1.7.0", "ethcore-util 1.7.0", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-rpc 1.7.0", "parity-ui 1.7.0", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1080,7 +1037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1092,7 +1049,7 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1105,7 +1062,7 @@ dependencies = [ [[package]] name = "jsonrpc-ipc-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1117,7 +1074,7 @@ dependencies = [ [[package]] name = "jsonrpc-macros" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1127,7 +1084,7 @@ dependencies = [ [[package]] name = "jsonrpc-minihttp-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1141,7 +1098,7 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1151,7 +1108,7 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1162,7 +1119,7 @@ dependencies = [ [[package]] name = "jsonrpc-tcp-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1172,6 +1129,17 @@ dependencies = [ "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-ws-server" +version = "7.0.0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#ad0682785a693eba3069e48b57ec89abb62c3b60" +dependencies = [ + "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "ws 0.6.0 (git+https://github.com/tomusdrw/ws-rs)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1708,16 +1676,60 @@ dependencies = [ "tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parity-rpc" +version = "1.7.0" +dependencies = [ + "cid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "ethash 1.7.0", + "ethcore 1.7.0", + "ethcore-devtools 1.7.0", + "ethcore-io 1.7.0", + "ethcore-ipc 1.7.0", + "ethcore-light 1.7.0", + "ethcore-logger 1.7.0", + "ethcore-util 1.7.0", + "ethcrypto 0.1.0", + "ethjson 0.1.0", + "ethkey 0.2.0", + "ethstore 0.1.0", + "ethsync 1.7.0", + "fetch 0.1.0", + "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "jsonrpc-minihttp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "jsonrpc-ws-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "multihash 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-reactor 0.1.0", + "parity-updater 1.7.0", + "rlp 0.1.0", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", + "stats 0.1.0", + "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parity-rpc-client" version = "1.4.0" dependencies = [ - "ethcore-rpc 1.7.0", "ethcore-signer 1.7.0", "ethcore-util 1.7.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-rpc 1.7.0", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2081,9 +2093,9 @@ name = "rpc-cli" version = "1.4.0" dependencies = [ "ethcore-bigint 0.1.2", - "ethcore-rpc 1.7.0", "ethcore-util 1.7.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-rpc 1.7.0", "parity-rpc-client 1.4.0", "rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2710,6 +2722,21 @@ dependencies = [ "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ws" +version = "0.6.0" +source = "git+https://github.com/tomusdrw/ws-rs#3259e7ca906c848beae109eb32e492871f8f397d" +dependencies = [ + "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -2824,6 +2851,7 @@ dependencies = [ "checksum jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "" "checksum jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "" "checksum jsonrpc-tcp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "" +"checksum jsonrpc-ws-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" @@ -2981,6 +3009,7 @@ dependencies = [ "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum ws 0.5.3 (git+https://github.com/paritytech/ws-rs.git?branch=parity-1.7)" = "" +"checksum ws 0.6.0 (git+https://github.com/tomusdrw/ws-rs)" = "" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77b831a5ba77110f438f0ac5583aafeb087f70432998ba6b7dcb1d32185db453" "checksum xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "65e74b96bd3179209dc70a980da6df843dff09e46eee103a0376c0949257e3ef" diff --git a/Cargo.toml b/Cargo.toml index 09af66e09..37effabb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,6 @@ ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethcore-io = { path = "util/io" } ethcore-devtools = { path = "devtools" } -ethcore-rpc = { path = "rpc" } ethcore-signer = { path = "signer" } ethcore-ipc = { path = "ipc/rpc" } ethcore-ipc-nano = { path = "ipc/nano" } @@ -45,12 +44,13 @@ ethkey = { path = "ethkey" } evmbin = { path = "evmbin" } rlp = { path = "util/rlp" } rpc-cli = { path = "rpc_cli" } -parity-rpc-client = { path = "rpc_client" } parity-hash-fetch = { path = "hash-fetch" } parity-ipfs-api = { path = "ipfs" } -parity-updater = { path = "updater" } -parity-reactor = { path = "util/reactor" } parity-local-store = { path = "local-store" } +parity-reactor = { path = "util/reactor" } +parity-rpc = { path = "rpc" } +parity-rpc-client = { path = "rpc_client" } +parity-updater = { path = "updater" } path = { path = "util/path" } parity-dapps = { path = "dapps", optional = true } @@ -85,7 +85,7 @@ ui-precompiled = [ dapps = ["parity-dapps"] ipc = ["ethcore/ipc", "ethsync/ipc"] jit = ["ethcore/jit"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "parity-dapps/dev", "ethcore-signer/dev"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "parity-rpc/dev", "parity-dapps/dev", "ethcore-signer/dev"] json-tests = ["ethcore/json-tests"] test-heavy = ["ethcore/test-heavy"] ethkey-cli = ["ethcore/ethkey-cli"] diff --git a/dapps/src/rpc.rs b/dapps/src/rpc.rs index b743408dc..74c6d8d89 100644 --- a/dapps/src/rpc.rs +++ b/dapps/src/rpc.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use hyper; -use ethcore_rpc::{Metadata, Origin}; +use parity_rpc::{Metadata, Origin}; use jsonrpc_core::{Middleware, MetaIoHandler}; use jsonrpc_http_server::{self as http, AccessControlAllowOrigin, HttpMetaExtractor}; use jsonrpc_http_server::tokio_core::reactor::Remote; diff --git a/parity/cli/config.full.toml b/parity/cli/config.full.toml index 7301afa50..64ddd20e9 100644 --- a/parity/cli/config.full.toml +++ b/parity/cli/config.full.toml @@ -52,6 +52,14 @@ cors = "null" apis = ["web3", "eth", "net", "parity", "traces", "rpc"] hosts = ["none"] +[websockets] +disable = false +port = 8546 +interface = "local" +origins = ["none"] +apis = ["web3", "eth", "net", "parity", "traces", "rpc"] +hosts = ["none"] + [ipc] disable = false path = "$HOME/.parity/jsonrpc.ipc" diff --git a/parity/cli/config.toml b/parity/cli/config.toml index b7f2936a1..b6695f3f5 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -24,6 +24,9 @@ allow_ips = "public" reserved_only = true reserved_peers = "./path/to/reserved_peers" +[websockets] +disable = true +origins = ["none"] [rpc] disable = true diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 002ce6efb..ed1b6526f 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -170,6 +170,20 @@ usage! { flag_jsonrpc_threads: Option = None, or |c: &Config| otry!(c.rpc).threads.map(Some), + // WS + flag_no_ws: bool = false, + or |c: &Config| otry!(c.websockets).disable.clone(), + flag_ws_port: u16 = 8546u16, + or |c: &Config| otry!(c.websockets).port.clone(), + flag_ws_interface: String = "local", + or |c: &Config| otry!(c.websockets).interface.clone(), + flag_ws_apis: String = "web3,eth,net,parity,traces,rpc", + or |c: &Config| otry!(c.websockets).apis.as_ref().map(|vec| vec.join(",")), + flag_ws_origins: String = "none", + or |c: &Config| otry!(c.websockets).origins.as_ref().map(|vec| vec.join(",")), + flag_ws_hosts: String = "none", + or |c: &Config| otry!(c.websockets).hosts.as_ref().map(|vec| vec.join(",")), + // IPC flag_no_ipc: bool = false, or |c: &Config| otry!(c.ipc).disable.clone(), @@ -363,6 +377,7 @@ struct Config { ui: Option, network: Option, rpc: Option, + websockets: Option, ipc: Option, dapps: Option, secretstore: Option, @@ -440,6 +455,16 @@ struct Rpc { threads: Option, } +#[derive(Default, Debug, PartialEq, RustcDecodable)] +struct Ws { + disable: Option, + port: Option, + interface: Option, + apis: Option>, + origins: Option>, + hosts: Option>, +} + #[derive(Default, Debug, PartialEq, RustcDecodable)] struct Ipc { disable: Option, @@ -554,7 +579,7 @@ struct Misc { mod tests { use super::{ Args, ArgsError, - Config, Operating, Account, Ui, Network, Rpc, Ipc, Dapps, Ipfs, Mining, Footprint, + Config, Operating, Account, Ui, Network, Ws, Rpc, Ipc, Dapps, Ipfs, Mining, Footprint, Snapshots, VM, Misc, SecretStore, }; use toml; @@ -699,6 +724,14 @@ mod tests { flag_jsonrpc_hosts: "none".into(), flag_jsonrpc_threads: None, + // WS + flag_no_ws: false, + flag_ws_port: 8546u16, + flag_ws_interface: "local".into(), + flag_ws_apis: "web3,eth,net,parity,traces,rpc".into(), + flag_ws_origins: "none".into(), + flag_ws_hosts: "none".into(), + // IPC flag_no_ipc: false, flag_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(), @@ -899,6 +932,14 @@ mod tests { reserved_only: Some(true), no_serve_light: None, }), + websockets: Some(Ws { + disable: Some(true), + port: None, + interface: None, + apis: None, + origins: Some(vec!["none".into()]), + hosts: None, + }), rpc: Some(Rpc { disable: Some(true), port: Some(8180), diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index 16f04e55e..17b6ce2b8 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -157,7 +157,28 @@ API and Console Options: vectors. Special options: "all", "none", (default: {flag_jsonrpc_hosts}). --jsonrpc-threads THREADS Enables experimental faster implementation of JSON-RPC server. - Requires Dapps server to be disabled using --no-dapps. (default: {flag_jsonrpc_threads:?}) + Requires Dapps server to be disabled + using --no-dapps. (default: {flag_jsonrpc_threads:?}) + + --no-ws Disable the WebSockets server. (default: {flag_no_ws}) + --ws-port PORT Specify the port portion of the WebSockets server + (default: {flag_ws_port}). + --ws-interface IP Specify the hostname portion of the WebSockets + server, IP should be an interface's IP address, or + all (all interfaces) or local (default: {flag_ws_interface}). + --ws-apis APIS Specify the APIs available through the WebSockets + interface. APIS is a comma-delimited list of API + name. Possible name are web3, eth, net, personal, + parity, parity_set, traces, rpc, parity_accounts. + (default: {flag_ws_apis}). + --ws-origins URL Specify Origin header values allowed to connect. + Special options: "all", "none". + (default: {flag_ws_origins}) + --ws-hosts HOSTS List of allowed Host header values. This option will + validate the Host header sent by the browser, it + is additional security against some attack + vectors. Special options: "all", "none", + (default: {flag_ws_hosts}). --no-ipc Disable JSON-RPC over IPC service. (default: {flag_no_ipc}) --ipc-path PATH Specify custom path for JSON-RPC over IPC service diff --git a/parity/configuration.rs b/parity/configuration.rs index fe26613d3..724633c28 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -30,9 +30,9 @@ use ethcore::client::{VMType}; use ethcore::miner::{MinerOptions, Banning, StratumOptions}; use ethcore::verification::queue::VerifierSettings; -use rpc::{IpcConfiguration, HttpConfiguration}; +use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration}; use rpc_apis::ApiSet; -use ethcore_rpc::NetworkSettings; +use parity_rpc::NetworkSettings; use cache::CacheConfig; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home, replace_home_for_db, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy}; @@ -114,6 +114,7 @@ impl Configuration { }; let update_policy = self.update_policy()?; let logger_config = self.logger_config(); + let ws_conf = self.ws_config()?; let http_conf = self.http_config()?; let ipc_conf = self.ipc_config()?; let net_conf = self.net_config()?; @@ -352,6 +353,7 @@ impl Configuration { daemon: daemon, logger_config: logger_config.clone(), miner_options: miner_options, + ws_conf: ws_conf, http_conf: http_conf, ipc_conf: ipc_conf, net_conf: net_conf, @@ -757,6 +759,14 @@ impl Configuration { Self::hosts(&self.args.flag_jsonrpc_hosts) } + fn ws_hosts(&self) -> Option> { + Self::hosts(&self.args.flag_ws_hosts) + } + + fn ws_origins(&self) -> Option> { + Self::hosts(&self.args.flag_ws_origins) + } + fn ipfs_hosts(&self) -> Option> { Self::hosts(&self.args.flag_ipfs_api_hosts) } @@ -801,6 +811,19 @@ impl Configuration { Ok(conf) } + fn ws_config(&self) -> Result { + let conf = WsConfiguration { + enabled: self.ws_enabled(), + interface: self.ws_interface(), + port: self.args.flag_ws_port, + apis: self.args.flag_ws_apis.parse()?, + hosts: self.ws_hosts(), + origins: self.ws_origins() + }; + + Ok(conf) + } + fn network_settings(&self) -> NetworkSettings { NetworkSettings { name: self.args.flag_identity.clone(), @@ -913,6 +936,10 @@ impl Configuration { Self::interface(&self.network_settings().rpc_interface) } + fn ws_interface(&self) -> String { + Self::interface(&self.args.flag_ws_interface) + } + fn ipfs_interface(&self) -> String { Self::interface(&self.args.flag_ipfs_api_interface) } @@ -965,6 +992,10 @@ impl Configuration { !self.args.flag_jsonrpc_off && !self.args.flag_no_jsonrpc } + fn ws_enabled(&self) -> bool { + !self.args.flag_no_ws + } + fn dapps_enabled(&self) -> bool { !self.args.flag_dapps_off && !self.args.flag_no_dapps && self.rpc_enabled() && cfg!(feature = "dapps") } @@ -1000,7 +1031,7 @@ impl Configuration { mod tests { use super::*; use cli::Args; - use ethcore_rpc::NetworkSettings; + use parity_rpc::NetworkSettings; use ethcore::client::{VMType, BlockId}; use ethcore::miner::{MinerOptions, PrioritizationStrategy}; use helpers::{default_network_config}; @@ -1204,6 +1235,7 @@ mod tests { daemon: None, logger_config: Default::default(), miner_options: Default::default(), + ws_conf: Default::default(), http_conf: Default::default(), ipc_conf: Default::default(), net_conf: default_network_config(), diff --git a/parity/dapps.rs b/parity/dapps.rs index 28264e270..b2dfe16d4 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -109,7 +109,7 @@ pub use self::server::{SyncStatus, Middleware, dapps_middleware}; mod server { use super::Dependencies; use std::path::PathBuf; - use ethcore_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction}; + use parity_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction}; pub type SyncStatus = Fn() -> bool; diff --git a/parity/informant.rs b/parity/informant.rs index 4145b0282..6b21eefc0 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -30,8 +30,8 @@ use ethcore::service::ClientIoMessage; use ethcore::snapshot::service::Service as SnapshotService; use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; use number_prefix::{binary_prefix, Standalone, Prefixed}; -use ethcore_rpc::{is_major_importing}; -use ethcore_rpc::informant::RpcStats; +use parity_rpc::{is_major_importing}; +use parity_rpc::informant::RpcStats; pub struct Informant { report: RwLock>, diff --git a/parity/main.rs b/parity/main.rs index 0d55055da..c61d414be 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -51,18 +51,18 @@ extern crate ethcore_ipc_hypervisor as hypervisor; extern crate ethcore_ipc_nano as nanoipc; extern crate ethcore_light as light; extern crate ethcore_logger; -extern crate ethcore_rpc; extern crate ethcore_signer; extern crate ethcore_util as util; extern crate ethkey; extern crate ethsync; extern crate parity_hash_fetch as hash_fetch; extern crate parity_ipfs_api; -extern crate parity_reactor; -extern crate parity_updater as updater; extern crate parity_local_store as local_store; -extern crate rpc_cli; +extern crate parity_reactor; +extern crate parity_rpc; +extern crate parity_updater as updater; extern crate path; +extern crate rpc_cli; #[macro_use] extern crate log as rlog; diff --git a/parity/rpc.rs b/parity/rpc.rs index 70a91c851..1fc503767 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -14,19 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::{io, fmt}; +use std::io; use std::sync::Arc; use dapps; use dir::default_data_path; -use ethcore_rpc::informant::{RpcStats, Middleware}; -use ethcore_rpc::{self as rpc, HttpServerError, Metadata, Origin, AccessControlAllowOrigin, Host}; +use parity_rpc::informant::{RpcStats, Middleware}; +use parity_rpc::{self as rpc, HttpServerError, Metadata, Origin, DomainsValidation}; use helpers::parity_ipc_path; use jsonrpc_core::MetaIoHandler; use parity_reactor::TokioRemote; use rpc_apis::{self, ApiSet}; -pub use ethcore_rpc::{IpcServer, HttpServer, RequestMiddleware}; +pub use parity_rpc::{IpcServer, HttpServer, RequestMiddleware}; +pub use parity_rpc::ws::Server as WsServer; #[derive(Debug, Clone, PartialEq)] pub struct HttpConfiguration { @@ -71,12 +72,25 @@ impl Default for IpcConfiguration { } } -impl fmt::Display for IpcConfiguration { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.enabled { - write!(f, "endpoint address [{}], api list [{:?}]", self.socket_addr, self.apis) - } else { - write!(f, "disabled") +#[derive(Debug, PartialEq)] +pub struct WsConfiguration { + pub enabled: bool, + pub interface: String, + pub port: u16, + pub apis: ApiSet, + pub origins: Option>, + pub hosts: Option>, +} + +impl Default for WsConfiguration { + fn default() -> Self { + WsConfiguration { + enabled: true, + interface: "127.0.0.1".into(), + port: 8546, + apis: ApiSet::UnsafeContext, + origins: Some(Vec::new()), + hosts: Some(Vec::new()), } } } @@ -112,12 +126,71 @@ impl rpc::IpcMetaExtractor for RpcExtractor { } } +impl rpc::ws::MetaExtractor for RpcExtractor { + fn extract(&self, req: &rpc::ws::RequestContext) -> Metadata { + let mut metadata = Metadata::default(); + let id = req.session_id as u64; + metadata.origin = Origin::Ws(id.into()); + metadata + } +} + +struct WsStats { + stats: Arc, +} + +impl rpc::ws::SessionStats for WsStats { + fn open_session(&self, _id: rpc::ws::SessionId) { + self.stats.open_session() + } + + fn close_session(&self, _id: rpc::ws::SessionId) { + self.stats.close_session() + } +} + fn setup_apis(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler> where D: rpc_apis::Dependencies { rpc_apis::setup_rpc(deps.stats.clone(), &*deps.apis, apis) } +pub fn new_ws( + conf: WsConfiguration, + deps: &Dependencies, +) -> Result, String> { + if !conf.enabled { + return Ok(None); + } + + let url = format!("{}:{}", conf.interface, conf.port); + let addr = url.parse().map_err(|_| format!("Invalid WebSockets listen host/port given: {}", url))?; + let handler = setup_apis(conf.apis, deps); + let remote = deps.remote.clone(); + let allowed_origins = into_domains(conf.origins); + let allowed_hosts = into_domains(conf.hosts); + + let start_result = rpc::start_ws( + &addr, + handler, + remote, + allowed_origins, + allowed_hosts, + RpcExtractor, + WsStats { + stats: deps.stats.clone(), + }, + ); + + match start_result { + Ok(server) => Ok(Some(server)), + Err(rpc::ws::Error::Io(ref err)) if err.kind() == io::ErrorKind::AddrInUse => Err( + format!("WebSockets address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --ws-port and --ws-interface options.", url) + ), + Err(e) => Err(format!("WebSockets error: {:?}", e)), + } +} + pub fn new_http( conf: HttpConfiguration, deps: &Dependencies, @@ -128,17 +201,17 @@ pub fn new_http( } let url = format!("{}:{}", conf.interface, conf.port); - let addr = url.parse().map_err(|_| format!("Invalid JSONRPC listen host/port given: {}", url))?; + let addr = url.parse().map_err(|_| format!("Invalid HTTP JSON-RPC listen host/port given: {}", url))?; let handler = setup_apis(conf.apis, deps); let remote = deps.remote.clone(); - let cors_domains: Option> = conf.cors.map(|domains| domains.into_iter().map(AccessControlAllowOrigin::from).collect()); - let allowed_hosts: Option> = conf.hosts.map(|hosts| hosts.into_iter().map(Host::from).collect()); + let cors_domains = into_domains(conf.cors); + let allowed_hosts = into_domains(conf.hosts); let start_result = rpc::start_http( &addr, - cors_domains.into(), - allowed_hosts.into(), + cors_domains, + allowed_hosts, handler, remote, RpcExtractor, @@ -153,16 +226,17 @@ pub fn new_http( match start_result { Ok(server) => Ok(Some(server)), - Err(HttpServerError::Io(err)) => match err.kind() { - io::ErrorKind::AddrInUse => Err( - format!("RPC address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --jsonrpc-port and --jsonrpc-interface options.", url) - ), - _ => Err(format!("RPC io error: {}", err)), - }, - Err(e) => Err(format!("RPC error: {:?}", e)), + Err(HttpServerError::Io(ref err)) if err.kind() == io::ErrorKind::AddrInUse => Err( + format!("HTTP address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --jsonrpc-port and --jsonrpc-interface options.", url) + ), + Err(e) => Err(format!("HTTP error: {:?}", e)), } } +fn into_domains>(items: Option>) -> DomainsValidation { + items.map(|vals| vals.into_iter().map(T::from).collect()).into() +} + pub fn new_ipc( conf: IpcConfiguration, dependencies: &Dependencies @@ -170,18 +244,19 @@ pub fn new_ipc( if !conf.enabled { return Ok(None); } + let handler = setup_apis(conf.apis, dependencies); let remote = dependencies.remote.clone(); match rpc::start_ipc(&conf.socket_addr, handler, remote, RpcExtractor) { Ok(server) => Ok(Some(server)), - Err(io_error) => Err(format!("RPC io error: {}", io_error)), + Err(io_error) => Err(format!("IPC error: {}", io_error)), } } #[cfg(test)] mod tests { use super::RpcExtractor; - use ethcore_rpc::{HttpMetaExtractor, Origin}; + use parity_rpc::{HttpMetaExtractor, Origin}; #[test] fn should_extract_rpc_origin() { diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 538808909..15fe660b2 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -20,15 +20,15 @@ use std::collections::HashSet; use std::str::FromStr; use std::sync::Arc; -pub use ethcore_rpc::SignerService; +pub use parity_rpc::SignerService; use ethcore::account_provider::AccountProvider; use ethcore::client::Client; use ethcore::miner::{Miner, ExternalMiner}; use ethcore::snapshot::SnapshotService; -use ethcore_rpc::{Metadata, NetworkSettings}; -use ethcore_rpc::informant::{ActivityNotifier, Middleware, RpcStats, ClientNotifier}; -use ethcore_rpc::dispatch::{FullDispatcher, LightDispatcher}; +use parity_rpc::{Metadata, NetworkSettings}; +use parity_rpc::informant::{ActivityNotifier, Middleware, RpcStats, ClientNotifier}; +use parity_rpc::dispatch::{FullDispatcher, LightDispatcher}; use ethsync::{ManageNetwork, SyncProvider, LightSync}; use hash_fetch::fetch::Client as FetchClient; use jsonrpc_core::{MetaIoHandler}; @@ -203,7 +203,7 @@ impl Dependencies for FullDependencies { } fn extend_with_set(&self, handler: &mut MetaIoHandler, apis: &[Api]) { - use ethcore_rpc::v1::*; + use parity_rpc::v1::*; macro_rules! add_signing_methods { ($namespace:ident, $handler:expr, $deps:expr) => { @@ -331,7 +331,7 @@ impl Dependencies for LightDependencies { fn activity_notifier(&self) -> Self::Notifier { LightClientNotifier } fn extend_with_set(&self, handler: &mut MetaIoHandler>, apis: &[Api]) { - use ethcore_rpc::v1::*; + use parity_rpc::v1::*; let dispatcher = LightDispatcher::new( self.sync.clone(), diff --git a/parity/run.rs b/parity/run.rs index 70a23f934..a76c6a4ca 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use std::net::{TcpListener}; use ctrlc::CtrlC; use fdlimit::raise_fd_limit; -use ethcore_rpc::{NetworkSettings, informant, is_major_importing}; +use parity_rpc::{NetworkSettings, informant, is_major_importing}; use ethsync::NetworkConfiguration; use util::{Colour, version, Mutex, Condvar}; use io::{MayPanic, ForwardPanic, PanicHandler}; @@ -80,6 +80,7 @@ pub struct RunCmd { pub daemon: Option, pub logger_config: LogConfig, pub miner_options: MinerOptions, + pub ws_conf: rpc::WsConfiguration, pub http_conf: rpc::HttpConfiguration, pub ipc_conf: rpc::IpcConfiguration, pub net_conf: NetworkConfiguration, @@ -295,7 +296,8 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc) -> }; // start rpc servers - let _http_server = rpc::new_http(cmd.http_conf, &dependencies, None)?; + let _ws_server = rpc::new_ws(cmd.ws_conf, &dependencies)?; + let _http_server = rpc::new_http(cmd.http_conf.clone(), &dependencies, None)?; let _ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; // the signer server @@ -636,6 +638,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?; // start rpc servers + let ws_server = rpc::new_ws(cmd.ws_conf, &dependencies)?; let http_server = rpc::new_http(cmd.http_conf.clone(), &dependencies, dapps_middleware)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; @@ -716,7 +719,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R let restart = wait_for_exit(panic_handler, Some(updater), Some(client), can_restart); // drop this stuff as soon as exit detected. - drop((http_server, ipc_server, signer_server, secretstore_key_server, ipfs_server, event_loop)); + drop((ws_server, http_server, ipc_server, signer_server, secretstore_key_server, ipfs_server, event_loop)); info!("Finishing work, please wait..."); diff --git a/parity/signer.rs b/parity/signer.rs index 29429311e..1ab53ea69 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -22,8 +22,8 @@ pub use ethcore_signer::Server as SignerServer; use ansi_term::Colour; use dir::default_data_path; -use ethcore_rpc::informant::RpcStats; -use ethcore_rpc::{self, ConfirmationsQueue}; +use parity_rpc::informant::RpcStats; +use parity_rpc::{self, ConfirmationsQueue}; use ethcore_signer as signer; use helpers::replace_home; use parity_reactor::TokioRemote; @@ -69,10 +69,10 @@ pub struct NewToken { #[derive(Debug, Default, Clone)] pub struct StandardExtractor; -impl signer::MetaExtractor for StandardExtractor { - fn extract_metadata(&self, session: &H256) -> ethcore_rpc::Metadata { - let mut metadata = ethcore_rpc::Metadata::default(); - metadata.origin = ethcore_rpc::Origin::Signer((*session).into()); +impl signer::MetaExtractor for StandardExtractor { + fn extract_metadata(&self, session: &H256) -> parity_rpc::Metadata { + let mut metadata = parity_rpc::Metadata::default(); + metadata.origin = parity_rpc::Origin::Signer((*session).into()); metadata } } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 8b694b765..87e340b02 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] -description = "Ethcore jsonrpc" -name = "ethcore-rpc" +description = "Parity JSON-RPC servers." +name = "parity-rpc" version = "1.7.0" license = "GPL-3.0" authors = ["Parity Technologies "] @@ -25,6 +25,7 @@ rust-crypto = "0.2.36" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-minihttp-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } +jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-ipc-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } diff --git a/rpc/rpctest/Cargo.toml b/rpc/rpctest/Cargo.toml index 369de1c99..258af2f39 100644 --- a/rpc/rpctest/Cargo.toml +++ b/rpc/rpctest/Cargo.toml @@ -8,10 +8,10 @@ authors = ["Parity Technologies "] [dependencies] ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" } docopt = "0.7" -rustc-serialize = "0.3" ethcore = { path = "../../ethcore" } ethcore-devtools = { path = "../../devtools" } -ethcore-rpc = { path = ".." } ethcore-util = { path = "../../util" } ethjson = { path = "../../json" } +parity-rpc = { path = ".." } +rustc-serialize = "0.3" serde_json = "0.8" diff --git a/rpc/rpctest/src/main.rs b/rpc/rpctest/src/main.rs index 6776a913a..d65d2462a 100644 --- a/rpc/rpctest/src/main.rs +++ b/rpc/rpctest/src/main.rs @@ -16,13 +16,13 @@ extern crate ctrlc; extern crate docopt; -extern crate rustc_serialize; -extern crate serde_json; -extern crate ethjson; -extern crate ethcore_util as util; extern crate ethcore; extern crate ethcore_devtools as devtools; -extern crate ethcore_rpc as rpc; +extern crate ethcore_util as util; +extern crate ethjson; +extern crate parity_rpc as rpc; +extern crate rustc_serialize; +extern crate serde_json; use std::collections::HashMap; use std::sync::{Arc, Mutex, Condvar}; diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 1d3f4285d..53b8f994c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -66,6 +66,8 @@ extern crate ethjson; #[cfg(test)] extern crate ethcore_devtools as devtools; +pub extern crate jsonrpc_ws_server as ws; + mod metadata; pub mod v1; @@ -73,7 +75,7 @@ pub use ipc::{Server as IpcServer, MetaExtractor as IpcMetaExtractor, RequestCon pub use http::{ hyper, RequestMiddleware, RequestMiddlewareAction, - AccessControlAllowOrigin, Host, + AccessControlAllowOrigin, Host, DomainsValidation }; pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, Metadata, Origin, informant, dispatch}; @@ -193,3 +195,28 @@ pub fn start_ipc( .session_metadata_extractor(extractor) .start(addr) } + +/// Start WS server and return `Server` handle. +pub fn start_ws( + addr: &SocketAddr, + handler: H, + remote: tokio_core::reactor::Remote, + allowed_origins: ws::DomainsValidation, + allowed_hosts: ws::DomainsValidation, + extractor: T, + stats: U, +) -> Result where + M: jsonrpc_core::Metadata, + S: jsonrpc_core::Middleware, + H: Into>, + T: ws::MetaExtractor, + U: ws::SessionStats, +{ + ws::ServerBuilder::new(handler) + .event_loop_remote(remote) + .allowed_origins(allowed_origins) + .allowed_hosts(allowed_hosts) + .session_meta_extractor(extractor) + .session_stats(stats) + .start(addr) +} diff --git a/rpc/src/v1/types/provenance.rs b/rpc/src/v1/types/provenance.rs index 1e014dd5f..81201f8e4 100644 --- a/rpc/src/v1/types/provenance.rs +++ b/rpc/src/v1/types/provenance.rs @@ -33,6 +33,9 @@ pub enum Origin { /// IPC server (includes session hash) #[serde(rename="ipc")] Ipc(H256), + /// WS server (includes session hash) + #[serde(rename="ws")] + Ws(H256), /// Signer (includes session hash) #[serde(rename="signer")] Signer(H256), @@ -53,6 +56,7 @@ impl fmt::Display for Origin { Origin::Rpc(ref origin) => write!(f, "RPC (service: {})", origin), Origin::Dapps(ref origin) => write!(f, "Dapp {}", origin), Origin::Ipc(ref session) => write!(f, "IPC (session: {})", session), + Origin::Ws(ref session) => write!(f, "WebSocket (session: {})", session), Origin::Signer(ref session) => write!(f, "UI (session: {})", session), Origin::Unknown => write!(f, "unknown origin"), } @@ -112,6 +116,7 @@ mod tests { let o3 = Origin::Ipc(5.into()); let o4 = Origin::Signer(10.into()); let o5 = Origin::Unknown; + let o6 = Origin::Ws(5.into()); // when let res1 = serde_json::to_string(&o1).unwrap(); @@ -119,6 +124,7 @@ mod tests { let res3 = serde_json::to_string(&o3).unwrap(); let res4 = serde_json::to_string(&o4).unwrap(); let res5 = serde_json::to_string(&o5).unwrap(); + let res6 = serde_json::to_string(&o6).unwrap(); // then assert_eq!(res1, r#"{"rpc":"test service"}"#); @@ -126,6 +132,7 @@ mod tests { assert_eq!(res3, r#"{"ipc":"0x0000000000000000000000000000000000000000000000000000000000000005"}"#); assert_eq!(res4, r#"{"signer":"0x000000000000000000000000000000000000000000000000000000000000000a"}"#); assert_eq!(res5, r#""unknown""#); + assert_eq!(res6, r#"{"ws":"0x0000000000000000000000000000000000000000000000000000000000000005"}"#); } #[test] diff --git a/rpc_cli/Cargo.toml b/rpc_cli/Cargo.toml index 8169d3b71..bb3588015 100644 --- a/rpc_cli/Cargo.toml +++ b/rpc_cli/Cargo.toml @@ -10,6 +10,6 @@ version = "1.4.0" futures = "0.1" rpassword = "0.3.0" ethcore-bigint = { path = "../util/bigint" } -ethcore-rpc = { path = "../rpc" } +parity-rpc = { path = "../rpc" } parity-rpc-client = { path = "../rpc_client" } ethcore-util = { path = "../util" } diff --git a/rpc_cli/src/lib.rs b/rpc_cli/src/lib.rs index 0cfb54353..8d00405b5 100644 --- a/rpc_cli/src/lib.rs +++ b/rpc_cli/src/lib.rs @@ -1,10 +1,10 @@ extern crate futures; - -extern crate ethcore_util as util; -extern crate ethcore_rpc as rpc; -extern crate ethcore_bigint as bigint; extern crate rpassword; +extern crate ethcore_util as util; +extern crate ethcore_bigint as bigint; + +extern crate parity_rpc as rpc; extern crate parity_rpc_client as client; use rpc::v1::types::{U256, ConfirmationRequest}; diff --git a/rpc_client/Cargo.toml b/rpc_client/Cargo.toml index 7b6be3bb2..c4e68acef 100644 --- a/rpc_client/Cargo.toml +++ b/rpc_client/Cargo.toml @@ -16,6 +16,6 @@ tempdir = "0.3.5" url = "1.2.0" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } ws = { git = "https://github.com/paritytech/ws-rs.git", branch = "parity-1.7" } -ethcore-rpc = { path = "../rpc" } +parity-rpc = { path = "../rpc" } ethcore-signer = { path = "../signer" } ethcore-util = { path = "../util" } diff --git a/rpc_client/src/lib.rs b/rpc_client/src/lib.rs index 7bc265250..e2f53e606 100644 --- a/rpc_client/src/lib.rs +++ b/rpc_client/src/lib.rs @@ -1,17 +1,17 @@ pub mod client; pub mod signer_client; -extern crate ws; extern crate ethcore_signer; -extern crate url; -extern crate futures; extern crate ethcore_util as util; -extern crate ethcore_rpc as rpc; +extern crate futures; +extern crate jsonrpc_core; +extern crate parity_rpc as rpc; +extern crate rand; extern crate serde; extern crate serde_json; -extern crate rand; extern crate tempdir; -extern crate jsonrpc_core; +extern crate url; +extern crate ws; #[macro_use] extern crate log; diff --git a/scripts/targets.sh b/scripts/targets.sh index 040485d85..f3ae6a2d5 100644 --- a/scripts/targets.sh +++ b/scripts/targets.sh @@ -6,7 +6,7 @@ export TARGETS=" -p ethcore \ -p ethcore-bigint\ -p parity-dapps \ - -p ethcore-rpc \ + -p parity-rpc \ -p ethcore-signer \ -p ethcore-util \ -p ethcore-network \ diff --git a/signer/Cargo.toml b/signer/Cargo.toml index bed1c461a..4f7c0f179 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -20,7 +20,7 @@ ws = { git = "https://github.com/paritytech/ws-rs.git", branch = "parity-1.7" } parity-dapps-glue = { version = "1.7", optional = true } ethcore-util = { path = "../util" } ethcore-io = { path = "../util/io" } -ethcore-rpc = { path = "../rpc" } +parity-rpc = { path = "../rpc" } ethcore-devtools = { path = "../devtools" } parity-ui = { path = "../dapps/ui", version = "1.4", optional = true } diff --git a/signer/src/lib.rs b/signer/src/lib.rs index d211e2eac..a1c935c5b 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -32,13 +32,13 @@ //! extern crate jsonrpc_core; //! extern crate jsonrpc_server_utils; //! extern crate ethcore_signer; -//! extern crate ethcore_rpc; +//! extern crate parity_rpc; //! //! use std::sync::Arc; //! use jsonrpc_core::IoHandler; //! use jsonrpc_server_utils::reactor::RpcEventLoop; //! use ethcore_signer::ServerBuilder; -//! use ethcore_rpc::ConfirmationsQueue; +//! use parity_rpc::ConfirmationsQueue; //! //! fn main() { //! let queue = Arc::new(ConfirmationsQueue::default()); @@ -55,11 +55,11 @@ extern crate log; extern crate env_logger; extern crate rand; -extern crate ethcore_util as util; -extern crate ethcore_rpc as rpc; extern crate ethcore_io as io; +extern crate ethcore_util as util; extern crate jsonrpc_core; extern crate jsonrpc_server_utils; +extern crate parity_rpc as rpc; extern crate ws; extern crate ethcore_devtools as devtools; From 0180b21dd17ce9caf921d6fb87aab314447a58f2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 18 Apr 2017 14:55:25 +0200 Subject: [PATCH 19/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f668f3218..c74b51a58 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Be sure to check out [our wiki][wiki-url] for more information. Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. -Parity comes with a built-in wallet. To access [Parity Wallet](http://127.0.0.1:8080/) simply go to http://127.0.0.1:8080/. It +Parity comes with a built-in wallet. To access [Parity Wallet](http://web3.site/) simply go to http://web3.site/ (if you don't have access to the internet, but still want to use the service, you can also use http://127.0.0.1:8180/). It includes various functionality allowing you to: - create and manage your Ethereum accounts; - manage your Ether and any Ethereum tokens; From b50fb71dd1d29dfde2a6c7e1830447cf30896c31 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Wed, 19 Apr 2017 14:30:00 +0200 Subject: [PATCH 20/29] EIP-86 (#4697) * EIP-86 * Disable EIP-86 auto activation for now --- ethcore/light/src/client/mod.rs | 7 ++ ethcore/res/ethereum/classic.json | 3 +- ethcore/res/ethereum/eip150_test.json | 3 +- ethcore/res/ethereum/eip161_test.json | 3 +- ethcore/res/ethereum/expanse.json | 3 +- ethcore/res/ethereum/foundation.json | 3 +- ethcore/res/ethereum/frontier_like_test.json | 3 +- ethcore/res/ethereum/frontier_test.json | 3 +- ethcore/res/ethereum/homestead_test.json | 3 +- ethcore/res/ethereum/morden.json | 3 +- ethcore/res/ethereum/olympic.json | 3 +- ethcore/res/ethereum/ropsten.json | 3 +- ethcore/res/ethereum/tests | 2 +- ethcore/res/ethereum/transition_test.json | 5 +- ethcore/res/null.json | 3 +- ethcore/src/client/client.rs | 21 ++-- ethcore/src/client/test_client.rs | 4 +- ethcore/src/client/traits.rs | 3 + ethcore/src/engines/authority_round.rs | 19 +-- ethcore/src/engines/basic_authority.rs | 17 +-- ethcore/src/engines/instant_seal.rs | 7 +- ethcore/src/engines/mod.rs | 17 +-- ethcore/src/engines/null_engine.rs | 4 +- ethcore/src/engines/tendermint/mod.rs | 19 +-- .../engines/validator_set/safe_contract.rs | 7 +- ethcore/src/ethereum/ethash.rs | 53 +++----- ethcore/src/evm/ext.rs | 13 +- ethcore/src/evm/instructions.rs | 3 + ethcore/src/evm/interpreter/gasometer.rs | 2 +- ethcore/src/evm/interpreter/mod.rs | 12 +- ethcore/src/evm/mod.rs | 2 +- ethcore/src/evm/schedule.rs | 16 ++- ethcore/src/evm/tests.rs | 4 +- ethcore/src/executive.rs | 77 ++++++++---- ethcore/src/externalities.rs | 20 +-- ethcore/src/json_tests/executive.rs | 15 ++- ethcore/src/json_tests/state.rs | 19 ++- ethcore/src/json_tests/transaction.rs | 24 ++-- ethcore/src/lib.rs | 1 + ethcore/src/miner/miner.rs | 15 ++- ethcore/src/spec/spec.rs | 5 + ethcore/src/state/mod.rs | 2 +- ethcore/src/tests/client.rs | 2 +- ethcore/src/tests/helpers.rs | 5 +- ethcore/src/types/transaction.rs | 116 +++++++++++++----- evmbin/src/ext.rs | 6 +- json/src/spec/params.rs | 3 + json/src/state/test.rs | 2 +- json/src/state/transaction.rs | 2 +- parity/rpc_apis.rs | 1 + rpc/src/v1/impls/eth.rs | 9 +- rpc/src/v1/impls/light/eth.rs | 7 +- rpc/src/v1/impls/light/parity.rs | 9 +- rpc/src/v1/impls/parity.rs | 11 +- rpc/src/v1/impls/parity_set.rs | 9 +- rpc/src/v1/tests/mocked/parity_set.rs | 2 +- rpc/src/v1/tests/mocked/signing.rs | 2 +- rpc/src/v1/types/transaction.rs | 49 ++++---- sync/src/tests/consensus.rs | 36 +++--- 59 files changed, 433 insertions(+), 289 deletions(-) diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 6d241f7fd..7e6213273 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -106,6 +106,9 @@ pub trait LightChainClient: Send + Sync { /// Get the `i`th CHT root. fn cht_root(&self, i: usize) -> Option; + + /// Get the EIP-86 transition block number. + fn eip86_transition(&self) -> u64; } /// Something which can be treated as a `LightChainClient`. @@ -384,4 +387,8 @@ impl LightChainClient for Client { fn cht_root(&self, i: usize) -> Option { Client::cht_root(self, i) } + + fn eip86_transition(&self) -> u64 { + self.engine().params().eip86_transition + } } diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index f6d30c4d6..f7cb4daca 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -30,7 +30,8 @@ "chainID": "0x3d", "forkBlock": "0x1d4c00", "forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/eip150_test.json b/ethcore/res/ethereum/eip150_test.json index 8331c8fc2..3091ee27b 100644 --- a/ethcore/res/ethereum/eip150_test.json +++ b/ethcore/res/ethereum/eip150_test.json @@ -24,7 +24,8 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", - "eip98Transition": "0x7fffffffffffffff" + "eip98Transition": "0x7fffffffffffffff", + "eip86Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/eip161_test.json b/ethcore/res/ethereum/eip161_test.json index 00885bae1..e6e8bf3bb 100644 --- a/ethcore/res/ethereum/eip161_test.json +++ b/ethcore/res/ethereum/eip161_test.json @@ -24,7 +24,8 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", - "eip98Transition": "0x7fffffffffffffff" + "eip98Transition": "0x7fffffffffffffff", + "eip86Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json index 3ec04052b..b7d22ac3e 100644 --- a/ethcore/res/ethereum/expanse.json +++ b/ethcore/res/ethereum/expanse.json @@ -30,7 +30,8 @@ "networkID": "0x1", "chainID": "0x2", "subprotocolName": "exp", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 54f10b70c..8253987f3 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -147,7 +147,8 @@ "networkID" : "0x1", "forkBlock": "0x1d4c00", "forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 7b73faa30..aab433033 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -143,7 +143,8 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index bf79729ba..6761c79f3 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -23,7 +23,8 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index 95bd85a94..25b061857 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -23,7 +23,8 @@ "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 22f253bf8..495849daf 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -30,7 +30,8 @@ "chainID": "0x3e", "forkBlock": "0x1b34d8", "forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index baf1c7d05..3d2e7baf9 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -23,7 +23,8 @@ "maximumExtraDataSize": "0x0400", "minGasLimit": "125000", "networkID" : "0x0", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 539168279..1e350d636 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -27,7 +27,8 @@ "networkID" : "0x3", "forkBlock": 641350, "forkCanonHash": "0x8033403e9fe5811a7b6d6b469905915de1c59207ce2172cbcf5d6ff14fa6a2eb", - "eip98Transition": "0x7fffffffffffff" + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index d52059307..ef191fdc6 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit d520593078fa0849dcd1f907e44ed0a616892e33 +Subproject commit ef191fdc61cf76cdb9cdc147465fb447304b0ed2 diff --git a/ethcore/res/ethereum/transition_test.json b/ethcore/res/ethereum/transition_test.json index 1b502f087..41251dc8c 100644 --- a/ethcore/res/ethereum/transition_test.json +++ b/ethcore/res/ethereum/transition_test.json @@ -139,11 +139,12 @@ } }, "params": { - "eip98Transition": "0x7fffffffffffffff", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", - "networkID" : "0x1" + "networkID" : "0x1", + "eip98Transition": "0x7fffffffffffff", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/null.json b/ethcore/res/null.json index 3ec7ce75e..ffb0ea061 100644 --- a/ethcore/res/null.json +++ b/ethcore/res/null.json @@ -7,7 +7,8 @@ "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", - "networkID" : "0x2" + "networkID" : "0x2", + "eip86Transition": "0x7fffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 2ad4fa8d6..e7755e4d0 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -960,7 +960,7 @@ impl BlockChainClient for Client { return Err(err.into()) } } - let lower = t.gas_required(&self.engine.schedule(&env_info)).into(); + let lower = t.gas_required(&self.engine.schedule(env_info.number)).into(); if cond(lower)? { trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower); return Ok(lower) @@ -1259,7 +1259,8 @@ impl BlockChainClient for Client { .collect(); match (transaction, previous_receipts) { (Some(transaction), Some(previous_receipts)) => { - Some(transaction_receipt(transaction, previous_receipts)) + let schedule = self.engine().schedule(block_number); + Some(transaction_receipt(&schedule, transaction, previous_receipts)) }, _ => None, } @@ -1501,11 +1502,15 @@ impl BlockChainClient for Client { }) .and_then(|a| if a.is_zero() { None } else { Some(a) }) } + + fn eip86_transition(&self) -> u64 { + self.engine().params().eip86_transition + } } impl MiningBlockChainClient for Client { fn latest_schedule(&self) -> Schedule { - self.engine.schedule(&self.latest_env_info()) + self.engine.schedule(self.latest_env_info().number) } fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { @@ -1655,7 +1660,7 @@ impl Drop for Client { /// Returns `LocalizedReceipt` given `LocalizedTransaction` /// and a vector of receipts from given block up to transaction index. -fn transaction_receipt(mut tx: LocalizedTransaction, mut receipts: Vec) -> LocalizedReceipt { +fn transaction_receipt(schedule: &Schedule, mut tx: LocalizedTransaction, mut receipts: Vec) -> LocalizedReceipt { assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided."); let sender = tx.sender(); @@ -1674,12 +1679,12 @@ fn transaction_receipt(mut tx: LocalizedTransaction, mut receipts: Vec) transaction_hash: transaction_hash, transaction_index: transaction_index, block_hash: block_hash, - block_number:block_number, + block_number: block_number, cumulative_gas_used: receipt.gas_used, gas_used: receipt.gas_used - prior_gas_used, contract_address: match tx.action { Action::Call(_) => None, - Action::Create => Some(contract_address(&sender, &tx.nonce)) + Action::Create => Some(contract_address(schedule.create_address, &sender, &tx.nonce, &tx.data.sha3())) }, logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry { entry: log, @@ -1734,6 +1739,7 @@ mod tests { #[test] fn should_return_correct_log_index() { use super::transaction_receipt; + use evm::schedule::Schedule; use ethkey::KeyPair; use log_entry::{LogEntry, LocalizedLogEntry}; use receipt::{Receipt, LocalizedReceipt}; @@ -1743,6 +1749,7 @@ mod tests { // given let key = KeyPair::from_secret_slice(&"test".sha3()).unwrap(); let secret = key.secret(); + let schedule = Schedule::new_homestead(); let block_number = 1; let block_hash = 5.into(); @@ -1786,7 +1793,7 @@ mod tests { }]; // when - let receipt = transaction_receipt(transaction, receipts); + let receipt = transaction_receipt(&schedule, transaction, receipts); // then assert_eq!(receipt, LocalizedReceipt { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 16f38203f..feda29107 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -353,7 +353,7 @@ pub fn get_temp_state_db() -> GuardedTempResult { impl MiningBlockChainClient for TestBlockChainClient { fn latest_schedule(&self) -> Schedule { - Schedule::new_post_eip150(24576, true, true, true) + Schedule::new_post_eip150(24576, true, true, true, true) } fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { @@ -756,6 +756,8 @@ impl BlockChainClient for TestBlockChainClient { fn registrar_address(&self) -> Option
{ None } fn registry_address(&self, _name: String) -> Option
{ None } + + fn eip86_transition(&self) -> u64 { u64::max_value() } } impl ProvingBlockChainClient for TestBlockChainClient { diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index a612d8a77..8ccd022e2 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -272,6 +272,9 @@ pub trait BlockChainClient : Sync + Send { /// Get the address of a particular blockchain service, if available. fn registry_address(&self, name: String) -> Option
; + + /// Get the EIP-86 transition block number. + fn eip86_transition(&self) -> u64; } impl IpcConfig for BlockChainClient { } diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 2e8e3932c..85c848d16 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -26,12 +26,11 @@ use account_provider::AccountProvider; use block::*; use spec::CommonParams; use engines::{Engine, Seal, EngineError}; -use header::Header; +use header::{Header, BlockNumber}; use error::{Error, TransactionError, BlockError}; use evm::Schedule; use ethjson; use io::{IoContext, IoHandler, TimerToken, IoService}; -use env_info::EnvInfo; use builtin::Builtin; use transaction::UnverifiedTransaction; use client::{Client, EngineClient}; @@ -241,8 +240,9 @@ impl Engine for AuthorityRound { ] } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { - Schedule::new_post_eip150(usize::max_value(), true, true, true) + fn schedule(&self, block_number: BlockNumber) -> Schedule { + let eip86 = block_number >= self.params.eip86_transition; + Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86) } fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { @@ -387,7 +387,6 @@ impl Engine for AuthorityRound { #[cfg(test)] mod tests { use util::*; - use env_info::EnvInfo; use header::Header; use error::{Error, BlockError}; use ethkey::Secret; @@ -408,15 +407,7 @@ mod tests { #[test] fn can_return_schedule() { let engine = Spec::new_test_round().engine; - let schedule = engine.schedule(&EnvInfo { - number: 10000000, - author: 0.into(), - timestamp: 0, - difficulty: 0.into(), - last_hashes: Arc::new(vec![]), - gas_used: 0.into(), - gas_limit: 0.into(), - }); + let schedule = engine.schedule(10000000); assert!(schedule.stack_limit > 0); } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 19867a648..43be5fe70 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -24,11 +24,10 @@ use block::*; use builtin::Builtin; use spec::CommonParams; use engines::{Engine, Seal}; -use env_info::EnvInfo; use error::{BlockError, Error}; use evm::Schedule; use ethjson; -use header::Header; +use header::{Header, BlockNumber}; use client::Client; use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, new_validator_set}; @@ -86,7 +85,7 @@ impl Engine for BasicAuthority { /// Additional engine-specific information for the user/developer concerning `header`. fn extra_info(&self, _header: &Header) -> BTreeMap { map!["signature".to_owned() => "TODO".to_owned()] } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { + fn schedule(&self, _block_number: BlockNumber) -> Schedule { Schedule::new_homestead() } @@ -181,7 +180,6 @@ impl Engine for BasicAuthority { mod tests { use util::*; use block::*; - use env_info::EnvInfo; use error::{BlockError, Error}; use tests::helpers::*; use account_provider::AccountProvider; @@ -206,16 +204,7 @@ mod tests { #[test] fn can_return_schedule() { let engine = new_test_authority().engine; - let schedule = engine.schedule(&EnvInfo { - number: 10000000, - author: 0.into(), - timestamp: 0, - difficulty: 0.into(), - last_hashes: Arc::new(vec![]), - gas_used: 0.into(), - gas_limit: 0.into(), - }); - + let schedule = engine.schedule(10000000); assert!(schedule.stack_limit > 0); } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 88672c6f4..702afde4f 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -18,10 +18,10 @@ use std::collections::BTreeMap; use util::{Address, HashMap}; use builtin::Builtin; use engines::{Engine, Seal}; -use env_info::EnvInfo; use spec::CommonParams; use evm::Schedule; use block::ExecutedBlock; +use header::BlockNumber; /// An engine which does not provide any consensus mechanism, just seals blocks internally. pub struct InstantSeal { @@ -58,8 +58,9 @@ impl Engine for InstantSeal { &self.builtins } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { - Schedule::new_post_eip150(usize::max_value(), true, true, true) + fn schedule(&self, block_number: BlockNumber) -> Schedule { + let eip86 = block_number >= self.params.eip86_transition; + Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86) } fn seals_internally(&self) -> Option { Some(true) } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 438b9bda0..4de76f079 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -39,10 +39,10 @@ use account_provider::AccountProvider; use block::ExecutedBlock; use builtin::Builtin; use env_info::EnvInfo; -use error::{Error, TransactionError}; +use error::Error; use spec::CommonParams; use evm::Schedule; -use header::Header; +use header::{Header, BlockNumber}; use transaction::{UnverifiedTransaction, SignedTransaction}; use client::Client; @@ -107,8 +107,8 @@ pub trait Engine : Sync + Send { /// Get the general parameters of the chain. fn params(&self) -> &CommonParams; - /// Get the EVM schedule for the given `env_info`. - fn schedule(&self, env_info: &EnvInfo) -> Schedule; + /// Get the EVM schedule for the given `block_number`. + fn schedule(&self, block_number: BlockNumber) -> Schedule; /// Builtin-contracts we would like to see in the chain. /// (In principle these are just hints for the engine since that has the last word on them.) @@ -156,14 +156,7 @@ pub trait Engine : Sync + Send { // TODO: Add flags for which bits of the transaction to check. // TODO: consider including State in the params. fn verify_transaction_basic(&self, t: &UnverifiedTransaction, _header: &Header) -> Result<(), Error> { - t.check_low_s()?; - - if let Some(n) = t.network_id() { - if n != self.params().chain_id { - return Err(TransactionError::InvalidNetworkId.into()); - } - } - + t.verify_basic(true, Some(self.params().network_id), true)?; Ok(()) } diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 0611fc08e..838ddf809 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -20,7 +20,7 @@ use builtin::Builtin; use engines::Engine; use spec::CommonParams; use evm::Schedule; -use env_info::EnvInfo; +use header::BlockNumber; /// An engine which does not provide any consensus mechanism and does not seal blocks. pub struct NullEngine { @@ -57,7 +57,7 @@ impl Engine for NullEngine { &self.builtins } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { + fn schedule(&self, _block_number: BlockNumber) -> Schedule { Schedule::new_homestead() } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index cb284d3c4..65e11d19e 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -30,9 +30,8 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use util::*; use client::{Client, EngineClient}; use error::{Error, BlockError}; -use header::Header; +use header::{Header, BlockNumber}; use builtin::Builtin; -use env_info::EnvInfo; use rlp::UntrustedRlp; use ethkey::{recover, public_to_address, Signature}; use account_provider::AccountProvider; @@ -405,8 +404,9 @@ impl Engine for Tendermint { ] } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { - Schedule::new_post_eip150(usize::max_value(), true, true, true) + fn schedule(&self, block_number: BlockNumber) -> Schedule { + let eip86 = block_number >= self.params.eip86_transition; + Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86) } fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { @@ -658,7 +658,6 @@ mod tests { use block::*; use error::{Error, BlockError}; use header::Header; - use env_info::EnvInfo; use ethkey::Secret; use client::chain_notify::ChainNotify; use miner::MinerService; @@ -740,15 +739,7 @@ mod tests { #[test] fn can_return_schedule() { let engine = Spec::new_test_tendermint().engine; - let schedule = engine.schedule(&EnvInfo { - number: 10000000, - author: 0.into(), - timestamp: 0, - difficulty: 0.into(), - last_hashes: Arc::new(vec![]), - gas_used: 0.into(), - gas_limit: 0.into(), - }); + let schedule = engine.schedule(10000000); assert!(schedule.stack_limit > 0); } diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 0a0eaecfd..a9388bbbf 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -196,6 +196,7 @@ mod tests { let s0 = Secret::from_slice(&"1".sha3()).unwrap(); let v0 = tap.insert_account(s0.clone(), "").unwrap(); let v1 = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "").unwrap(); + let network_id = Spec::new_validator_safe_contract().network_id(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap)); client.engine().register_client(Arc::downgrade(&client)); let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap(); @@ -209,7 +210,7 @@ mod tests { action: Action::Call(validator_contract), value: 0.into(), data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), - }.sign(&s0, None); + }.sign(&s0, Some(network_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); client.update_sealing(); assert_eq!(client.chain_info().best_block_number, 1); @@ -221,7 +222,7 @@ mod tests { action: Action::Call(validator_contract), value: 0.into(), data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), - }.sign(&s0, None); + }.sign(&s0, Some(network_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); client.update_sealing(); // The transaction is not yet included so still unable to seal. @@ -240,7 +241,7 @@ mod tests { action: Action::Call(Address::default()), value: 0.into(), data: Vec::new(), - }.sign(&s0, None); + }.sign(&s0, Some(network_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); client.update_sealing(); // Able to seal again. diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 88655fa86..ae865da4f 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -19,8 +19,8 @@ use util::*; use block::*; use builtin::Builtin; use env_info::EnvInfo; -use error::{BlockError, TransactionError, Error}; -use header::Header; +use error::{BlockError, Error, TransactionError}; +use header::{Header, BlockNumber}; use state::CleanupMode; use spec::CommonParams; use transaction::UnverifiedTransaction; @@ -167,19 +167,20 @@ impl Engine for Ethash { map!["nonce".to_owned() => format!("0x{}", header.nonce().hex()), "mixHash".to_owned() => format!("0x{}", header.mix_hash().hex())] } - fn schedule(&self, env_info: &EnvInfo) -> Schedule { + fn schedule(&self, block_number: BlockNumber) -> Schedule { trace!(target: "client", "Creating schedule. fCML={}, bGCML={}", self.ethash_params.homestead_transition, self.ethash_params.eip150_transition); - if env_info.number < self.ethash_params.homestead_transition { + if block_number < self.ethash_params.homestead_transition { Schedule::new_frontier() - } else if env_info.number < self.ethash_params.eip150_transition { + } else if block_number < self.ethash_params.eip150_transition { Schedule::new_homestead() } else { Schedule::new_post_eip150( self.ethash_params.max_code_size as usize, - env_info.number >= self.ethash_params.eip160_transition, - env_info.number >= self.ethash_params.eip161abc_transition, - env_info.number >= self.ethash_params.eip161d_transition + block_number >= self.ethash_params.eip160_transition, + block_number >= self.ethash_params.eip161abc_transition, + block_number >= self.ethash_params.eip161d_transition, + block_number >= self.params.eip86_transition ) } } @@ -369,20 +370,13 @@ impl Engine for Ethash { } fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> { - if header.number() >= self.ethash_params.homestead_transition { - t.check_low_s()?; - } - - if let Some(n) = t.network_id() { - if header.number() < self.ethash_params.eip155_transition || n != self.params().chain_id { - return Err(TransactionError::InvalidNetworkId.into()) - } - } - if header.number() >= self.ethash_params.min_gas_price_transition && t.gas_price < self.ethash_params.min_gas_price { return Err(TransactionError::InsufficientGasPrice { minimal: self.ethash_params.min_gas_price, got: t.gas_price }.into()); } + let check_low_s = header.number() >= self.ethash_params.homestead_transition; + let network_id = if header.number() >= self.ethash_params.eip155_transition { Some(self.params().chain_id) } else { None }; + t.verify_basic(check_low_s, network_id, false)?; Ok(()) } } @@ -512,7 +506,6 @@ mod tests { use block::*; use tests::helpers::*; use engines::Engine; - use env_info::EnvInfo; use error::{BlockError, Error}; use header::Header; use super::super::{new_morden, new_homestead_test}; @@ -559,28 +552,10 @@ mod tests { #[test] fn can_return_schedule() { let engine = new_morden().engine; - let schedule = engine.schedule(&EnvInfo { - number: 10000000, - author: 0.into(), - timestamp: 0, - difficulty: 0.into(), - last_hashes: Arc::new(vec![]), - gas_used: 0.into(), - gas_limit: 0.into(), - }); - + let schedule = engine.schedule(10000000); assert!(schedule.stack_limit > 0); - let schedule = engine.schedule(&EnvInfo { - number: 100, - author: 0.into(), - timestamp: 0, - difficulty: 0.into(), - last_hashes: Arc::new(vec![]), - gas_used: 0.into(), - gas_limit: 0.into(), - }); - + let schedule = engine.schedule(100); assert!(!schedule.have_delegate_call); } diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index 352ffb7d9..e6b644874 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -41,6 +41,17 @@ pub enum MessageCallResult { Failed } +/// Specifies how an address is calculated for a new contract. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum CreateContractAddress { + /// Address is calculated from nonce and sender. Pre EIP-86 (Metropolis) + FromSenderAndNonce, + /// Address is calculated from code hash. Default since EIP-86 + FromCodeHash, + /// Address is calculated from code hash and sender. Used by CREATE_P2SH instruction. + FromSenderAndCodeHash, +} + /// Externalities interface for EVMs // TODO: [rob] associated error type instead of `trie::Result`. Not all EVMs are trie powered. pub trait Ext { @@ -68,7 +79,7 @@ pub trait Ext { /// Creates new contract. /// /// Returns gas_left and contract address if contract creation was succesfull. - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult; + fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address: CreateContractAddress) -> ContractCreateResult; /// Message call. /// diff --git a/ethcore/src/evm/instructions.rs b/ethcore/src/evm/instructions.rs index d93ddc437..41c9e1ea1 100644 --- a/ethcore/src/evm/instructions.rs +++ b/ethcore/src/evm/instructions.rs @@ -278,6 +278,7 @@ lazy_static! { arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero); arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special); arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special); + arr[CREATE_P2SH as usize] = InstructionInfo::new("CREATE_P2SH", 0, 3, 1, true, GasPriceTier::Special); arr }; } @@ -553,6 +554,8 @@ pub const CALLCODE: Instruction = 0xf2; pub const RETURN: Instruction = 0xf3; /// like CALLCODE but keeps caller's value and sender pub const DELEGATECALL: Instruction = 0xf4; +/// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160 +pub const CREATE_P2SH: Instruction = 0xfb; /// halt execution and register account for later deletion pub const SUICIDE: Instruction = 0xff; diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index 9086200fa..fb0c86d35 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -223,7 +223,7 @@ impl Gasometer { Request::GasMemProvide(gas, mem, Some(requested)) }, - instructions::CREATE => { + instructions::CREATE | instructions::CREATE_P2SH => { let gas = Gas::from(schedule.create_gas); let mem = mem_needed(stack.peek(1), stack.peek(2))?; diff --git a/ethcore/src/evm/interpreter/mod.rs b/ethcore/src/evm/interpreter/mod.rs index 79304793e..7fbab7ebc 100644 --- a/ethcore/src/evm/interpreter/mod.rs +++ b/ethcore/src/evm/interpreter/mod.rs @@ -32,7 +32,7 @@ use std::marker::PhantomData; use action_params::{ActionParams, ActionValue}; use types::executed::CallType; use evm::instructions::{self, Instruction, InstructionInfo}; -use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType}; +use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType, CreateContractAddress}; use bit_set::BitSet; use util::*; @@ -182,7 +182,9 @@ impl Interpreter { fn verify_instruction(&self, ext: &evm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack) -> evm::Result<()> { let schedule = ext.schedule(); - if !schedule.have_delegate_call && instruction == instructions::DELEGATECALL { + if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) || + (instruction == instructions::CREATE_P2SH && !schedule.have_create_p2sh) { + return Err(evm::Error::BadInstruction { instruction: instruction }); @@ -266,10 +268,12 @@ impl Interpreter { instructions::JUMPDEST => { // ignore }, - instructions::CREATE => { + instructions::CREATE | instructions::CREATE_P2SH => { let endowment = stack.pop_back(); let init_off = stack.pop_back(); let init_size = stack.pop_back(); + + let address_scheme = if instruction == instructions::CREATE { ext.schedule().create_address } else { CreateContractAddress::FromSenderAndCodeHash }; let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed"); let contract_code = self.mem.read_slice(init_off, init_size); @@ -280,7 +284,7 @@ impl Interpreter { return Ok(InstructionResult::UnusedGas(create_gas)); } - let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code); + let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme); return match create_result { ContractCreateResult::Created(address, gas_left) => { stack.push(address_to_u256(address)); diff --git a/ethcore/src/evm/mod.rs b/ethcore/src/evm/mod.rs index cc707d6ef..7906b81ff 100644 --- a/ethcore/src/evm/mod.rs +++ b/ethcore/src/evm/mod.rs @@ -32,7 +32,7 @@ mod tests; mod benches; pub use self::evm::{Evm, Error, Finalize, GasLeft, Result, CostType}; -pub use self::ext::{Ext, ContractCreateResult, MessageCallResult}; +pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; pub use self::factory::{Factory, VMType}; pub use self::schedule::Schedule; pub use types::executed::CallType; diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index 70801983d..97df4d784 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . //! Cost schedule and other parameterisations for the EVM. +use evm::CreateContractAddress; /// Definition of the cost schedule and other parameterisations for the EVM. pub struct Schedule { @@ -22,6 +23,8 @@ pub struct Schedule { pub exceptional_failed_code_deposit: bool, /// Does it have a delegate cal pub have_delegate_call: bool, + /// Does it have a CREATE_P2SH instruction + pub have_create_p2sh: bool, /// VM stack limit pub stack_limit: usize, /// Max number of nested calls/creates @@ -99,6 +102,8 @@ pub struct Schedule { pub no_empty: bool, /// Kill empty accounts if touched. pub kill_empty: bool, + /// Contract address generation scheme + pub create_address: CreateContractAddress, } impl Schedule { @@ -113,10 +118,11 @@ impl Schedule { } /// Schedule for the post-EIP-150-era of the Ethereum main net. - pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule { + pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, have_create_p2sh: bool) -> Schedule { Schedule { exceptional_failed_code_deposit: true, have_delegate_call: true, + have_create_p2sh: have_create_p2sh, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -155,13 +161,20 @@ impl Schedule { sub_gas_cap_divisor: Some(64), no_empty: no_empty, kill_empty: kill_empty, + create_address: if have_create_p2sh { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }, } } + /// Schedule for the Metropolis of the Ethereum main net. + pub fn new_metropolis() -> Schedule { + Self::new_post_eip150(24576, true, true, true, true) + } + fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { Schedule { exceptional_failed_code_deposit: efcd, have_delegate_call: hdc, + have_create_p2sh: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -200,6 +213,7 @@ impl Schedule { sub_gas_cap_divisor: None, no_empty: false, kill_empty: false, + create_address: CreateContractAddress::FromSenderAndNonce, } } } diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 3002c170c..b5b2341aa 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -18,7 +18,7 @@ use util::*; use action_params::{ActionParams, ActionValue}; use env_info::EnvInfo; use types::executed::CallType; -use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult}; +use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; use std::fmt::Debug; pub struct FakeLogEntry { @@ -111,7 +111,7 @@ impl Ext for FakeExt { self.blockhashes.get(number).unwrap_or(&H256::new()).clone() } - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { + fn create(&mut self, gas: &U256, value: &U256, code: &[u8], _address: CreateContractAddress) -> ContractCreateResult { self.calls.insert(FakeCall { call_type: FakeCallType::Create, gas: *gas, diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 5e0ee5662..dc9dcec17 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -22,7 +22,7 @@ use engines::Engine; use types::executed::CallType; use env_info::EnvInfo; use error::ExecutionError; -use evm::{self, Ext, Factory, Finalize}; +use evm::{self, Ext, Factory, Finalize, CreateContractAddress}; use externalities::*; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; use transaction::{Action, SignedTransaction}; @@ -34,14 +34,29 @@ pub use types::executed::{Executed, ExecutionResult}; /// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp` const STACK_SIZE_PER_DEPTH: usize = 24*1024; -/// Returns new address created from address and given nonce. -pub fn contract_address(address: &Address, nonce: &U256) -> Address { +/// Returns new address created from address, nonce, and code hash +pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code_hash: &H256) -> Address { use rlp::RlpStream; - let mut stream = RlpStream::new_list(2); - stream.append(address); - stream.append(nonce); - From::from(stream.out().sha3()) + match address_scheme { + CreateContractAddress::FromSenderAndNonce => { + let mut stream = RlpStream::new_list(2); + stream.append(sender); + stream.append(nonce); + From::from(stream.as_raw().sha3()) + }, + CreateContractAddress::FromCodeHash => { + let mut buffer = [0u8; 20 + 32]; + &mut buffer[20..].copy_from_slice(&code_hash[..]); + From::from((&buffer[..]).sha3()) + }, + CreateContractAddress::FromSenderAndCodeHash => { + let mut buffer = [0u8; 20 + 32]; + &mut buffer[..20].copy_from_slice(&sender[..]); + &mut buffer[20..].copy_from_slice(&code_hash[..]); + From::from((&buffer[..]).sha3()) + }, + } } /// Transaction execution options. @@ -125,7 +140,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let sender = t.sender(); let nonce = self.state.nonce(&sender)?; - let schedule = self.engine.schedule(self.info); + let schedule = self.engine.schedule(self.info.number); let base_gas_required = U256::from(t.gas_required(&schedule)); if t.gas < base_gas_required { @@ -160,17 +175,20 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { } // NOTE: there can be no invalid transactions from this point. - self.state.inc_nonce(&sender)?; + if !t.is_unsigned() { + self.state.inc_nonce(&sender)?; + } self.state.sub_balance(&sender, &U256::from(gas_cost))?; let mut substate = Substate::new(); let (gas_left, output) = match t.action { Action::Create => { - let new_address = contract_address(&sender, &nonce); + let code_hash = t.data.sha3(); + let new_address = contract_address(schedule.create_address, &sender, &nonce, &code_hash); let params = ActionParams { code_address: new_address.clone(), - code_hash: t.data.sha3(), + code_hash: code_hash, address: new_address, sender: sender.clone(), origin: sender.clone(), @@ -253,7 +271,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { // backup used in case of running out of gas self.state.checkpoint(); - let schedule = self.engine.schedule(self.info); + let schedule = self.engine.schedule(self.info.number); // at first, transfer value to destination if let ActionValue::Transfer(val) = params.value { @@ -365,8 +383,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { params: ActionParams, substate: &mut Substate, tracer: &mut T, - vm_tracer: &mut V + vm_tracer: &mut V, ) -> evm::Result where T: Tracer, V: VMTracer { + + let schedule = self.engine.schedule(self.info.number); + if schedule.create_address != CreateContractAddress::FromSenderAndNonce && self.state.exists(¶ms.address)? { + return Err(evm::Error::OutOfGas); + } + // backup used in case of running out of gas self.state.checkpoint(); @@ -374,7 +398,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut unconfirmed_substate = Substate::new(); // create contract and transfer value to it if necessary - let schedule = self.engine.schedule(self.info); let nonce_offset = if schedule.no_empty {1} else {0}.into(); let prev_bal = self.state.balance(¶ms.address)?; if let ActionValue::Transfer(val) = params.value { @@ -423,7 +446,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { trace: Vec, vm_trace: Option ) -> ExecutionResult { - let schedule = self.engine.schedule(self.info); + let schedule = self.engine.schedule(self.info.number); // refunds from SSTORE nonzero -> zero let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.sstore_clears_count; @@ -525,7 +548,7 @@ mod tests { use util::bytes::BytesRef; use action_params::{ActionParams, ActionValue}; use env_info::EnvInfo; - use evm::{Factory, VMType}; + use evm::{Factory, VMType, CreateContractAddress}; use error::ExecutionError; use state::{Substate, CleanupMode}; use tests::helpers::*; @@ -540,14 +563,14 @@ mod tests { fn test_contract_address() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let expected_address = Address::from_str("3f09c73a5ed19289fb9bdc72f1742566df146f56").unwrap(); - assert_eq!(expected_address, contract_address(&address, &U256::from(88))); + assert_eq!(expected_address, contract_address(CreateContractAddress::FromSenderAndNonce, &address, &U256::from(88), &H256::default())); } // TODO: replace params with transactions! evm_test!{test_sender_balance: test_sender_balance_jit, test_sender_balance_int} fn test_sender_balance(factory: Factory) { let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let address = contract_address(&sender, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); @@ -602,7 +625,7 @@ mod tests { let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let address = contract_address(&sender, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); let mut params = ActionParams::default(); @@ -658,7 +681,7 @@ mod tests { let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let address = contract_address(&sender, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); let mut params = ActionParams::default(); @@ -770,7 +793,7 @@ mod tests { let code = "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let address = contract_address(&sender, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); let mut params = ActionParams::default(); @@ -857,7 +880,7 @@ mod tests { let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d600360e6f0600055".from_hex().unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let address = contract_address(&sender, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); let mut params = ActionParams::default(); @@ -909,8 +932,8 @@ mod tests { let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0".from_hex().unwrap(); let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let address = contract_address(&sender, &U256::zero()); - let next_address = contract_address(&address, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); + let next_address = contract_address(CreateContractAddress::FromSenderAndNonce, &address, &U256::zero(), &H256::default()); let mut params = ActionParams::default(); params.address = address.clone(); params.sender = sender.clone(); @@ -1017,7 +1040,7 @@ mod tests { // 55 - sstore let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap(); - let address = contract_address(&sender, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); let mut params = ActionParams::default(); params.address = address.clone(); params.gas = U256::from(100_000); @@ -1052,7 +1075,7 @@ mod tests { nonce: U256::zero() }.sign(keypair.secret(), None); let sender = t.sender(); - let contract = contract_address(&sender, &U256::zero()); + let contract = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty).unwrap(); @@ -1181,7 +1204,7 @@ mod tests { let code = "6064640fffffffff20600055".from_hex().unwrap(); let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let address = contract_address(&sender, &U256::zero()); + let address = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); // TODO: add tests for 'callcreate' //let next_address = contract_address(&address, &U256::zero()); let mut params = ActionParams::default(); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 8591f15fd..0b849033e 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -21,8 +21,9 @@ use state::{Backend as StateBackend, State, Substate}; use engines::Engine; use env_info::EnvInfo; use executive::*; -use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory}; +use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory, CreateContractAddress}; use types::executed::CallType; +use types::transaction::UNSIGNED_SENDER; use trace::{Tracer, VMTracer}; /// Policy for handling output data on `RETURN` opcode. @@ -97,7 +98,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> depth: depth, origin_info: origin_info, substate: substate, - schedule: engine.schedule(env_info), + schedule: engine.schedule(env_info.number), output: output, tracer: tracer, vm_tracer: vm_tracer, @@ -147,10 +148,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> } } - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { + fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address_scheme: CreateContractAddress) -> ContractCreateResult { // create new contract address + let code_hash = code.sha3(); let address = match self.state.nonce(&self.origin_info.address) { - Ok(nonce) => contract_address(&self.origin_info.address, &nonce), + Ok(nonce) => contract_address(address_scheme, &self.origin_info.address, &nonce, &code_hash), Err(e) => { debug!(target: "ext", "Database corruption encountered: {:?}", e); return ContractCreateResult::Failed @@ -167,14 +169,16 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> gas_price: self.origin_info.gas_price, value: ActionValue::Transfer(*value), code: Some(Arc::new(code.to_vec())), - code_hash: code.sha3(), + code_hash: code_hash, data: None, call_type: CallType::None, }; - if let Err(e) = self.state.inc_nonce(&self.origin_info.address) { - debug!(target: "ext", "Database corruption encountered: {:?}", e); - return ContractCreateResult::Failed + if params.sender != UNSIGNED_SENDER { + if let Err(e) = self.state.inc_nonce(&self.origin_info.address) { + debug!(target: "ext", "Database corruption encountered: {:?}", e); + return ContractCreateResult::Failed + } } let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth); diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 9526e5ec2..c34ad69e3 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -21,7 +21,7 @@ use executive::*; use engines::Engine; use env_info::EnvInfo; use evm; -use evm::{Schedule, Ext, Factory, Finalize, VMType, ContractCreateResult, MessageCallResult}; +use evm::{Schedule, Ext, Factory, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; use externalities::*; use types::executed::CallType; use tests::helpers::*; @@ -56,7 +56,8 @@ struct TestExt<'a, T: 'a, V: 'a, B: 'a> { ext: Externalities<'a, T, V, B>, callcreates: Vec, - contract_address: Address + nonce: U256, + sender: Address, } impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B> @@ -76,9 +77,10 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B> vm_tracer: &'a mut V, ) -> trie::Result { Ok(TestExt { - contract_address: contract_address(&address, &state.nonce(&address)?), + nonce: state.nonce(&address)?, ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer, vm_tracer), - callcreates: vec![] + callcreates: vec![], + sender: address, }) } } @@ -114,14 +116,15 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B> self.ext.blockhash(number) } - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { + fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address: CreateContractAddress) -> ContractCreateResult { self.callcreates.push(CallCreate { data: code.to_vec(), destination: None, gas_limit: *gas, value: *value }); - ContractCreateResult::Created(self.contract_address.clone(), *gas) + let contract_address = contract_address(address, &self.sender, &self.nonce, &code.sha3()); + ContractCreateResult::Created(contract_address, *gas) } fn call(&mut self, diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index d0b18d99c..c15847896 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -21,6 +21,8 @@ use ethereum; use spec::Spec; use ethjson; use ethjson::state::test::ForkSpec; +use types::transaction::SignedTransaction; +use env_info::EnvInfo; lazy_static! { pub static ref FRONTIER: Spec = ethereum::new_frontier_test(); @@ -37,7 +39,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { for (name, test) in tests.into_iter() { { let multitransaction = test.transaction; - let env = test.env.into(); + let env: EnvInfo = test.env.into(); let pre: PodState = test.pre_state.into(); for (spec, states) in test.post_states { @@ -54,12 +56,15 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { let info = format!(" - {} | {:?} ({}/{}) ...", name, spec, i + 1, total); let post_root: H256 = state.hash.into(); - let transaction = multitransaction.select(&state.indexes).into(); - + let transaction: SignedTransaction = multitransaction.select(&state.indexes).into(); let mut state = get_temp_state(); state.populate_from(pre.clone()); - state.commit().expect(&format!("State test {} failed due to internal error.", name)); - let _res = state.apply(&env, &**engine, &transaction, false); + if transaction.verify_basic(true, None, env.number >= engine.params().eip86_transition).is_ok() { + state.commit().expect(&format!("State test {} failed due to internal error.", name)); + let _res = state.apply(&env, &**engine, &transaction, false); + } else { + let _rest = state.commit(); + } if state.root() != &post_root { println!("{} !!! State mismatch (got: {}, expect: {}", info, state.root(), post_root); flushln!("{} fail", info); @@ -73,7 +78,9 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec { } - println!("!!! {:?} tests from failed.", failed.len()); + if !failed.is_empty() { + println!("!!! {:?} tests failed.", failed.len()); + } failed } diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index f400180ee..a3c3c889d 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -18,35 +18,37 @@ use super::test_common::*; use evm; use ethjson; use rlp::UntrustedRlp; -use transaction::{Action, UnverifiedTransaction}; -use ethstore::ethkey::public_to_address; +use transaction::{Action, UnverifiedTransaction, SignedTransaction}; fn do_json_test(json_data: &[u8]) -> Vec { let tests = ethjson::transaction::Test::load(json_data).unwrap(); let mut failed = Vec::new(); - let old_schedule = evm::Schedule::new_frontier(); - let new_schedule = evm::Schedule::new_homestead(); + let frontier_schedule = evm::Schedule::new_frontier(); + let homestead_schedule = evm::Schedule::new_homestead(); + let metropolis_schedule = evm::Schedule::new_metropolis(); for (name, test) in tests.into_iter() { let mut fail_unless = |cond: bool, title: &str| if !cond { failed.push(name.clone()); println!("Transaction failed: {:?}: {:?}", name, title); }; let number: Option = test.block_number.map(Into::into); let schedule = match number { - None => &old_schedule, - Some(x) if x < 1_150_000 => &old_schedule, - Some(_) => &new_schedule + None => &frontier_schedule, + Some(x) if x < 1_150_000 => &frontier_schedule, + Some(x) if x < 3_000_000 => &homestead_schedule, + Some(_) => &metropolis_schedule }; let allow_network_id_of_one = number.map_or(false, |n| n >= 2_675_000); + let allow_unsigned = number.map_or(false, |n| n >= 3_000_000); let rlp: Vec = test.rlp.into(); let res = UntrustedRlp::new(&rlp) .as_val() .map_err(From::from) - .and_then(|t: UnverifiedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_network_id_of_one)); + .and_then(|t: UnverifiedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_network_id_of_one, allow_unsigned)); fail_unless(test.transaction.is_none() == res.is_err(), "Validity different"); if let (Some(tx), Some(sender)) = (test.transaction, test.sender) { let t = res.unwrap(); - fail_unless(public_to_address(&t.recover_public().unwrap()) == sender.into(), "sender mismatch"); + fail_unless(SignedTransaction::new(t.clone()).unwrap().sender() == sender.into(), "sender mismatch"); let is_acceptable_network_id = match t.network_id() { None => true, Some(1) if allow_network_id_of_one => true, @@ -84,3 +86,7 @@ declare_test!{TransactionTests_Homestead_ttTransactionTestEip155VitaliksTests, " declare_test!{TransactionTests_EIP155_ttTransactionTest, "TransactionTests/EIP155/ttTransactionTest"} declare_test!{TransactionTests_EIP155_ttTransactionTestEip155VitaliksTests, "TransactionTests/EIP155/ttTransactionTestEip155VitaliksTests"} declare_test!{TransactionTests_EIP155_ttTransactionTestVRule, "TransactionTests/EIP155/ttTransactionTestVRule"} + +declare_test!{TransactionTests_Metropolis_ttMetropolisTest, "TransactionTests/Metropolis/ttMetropolisTest"} +declare_test!{TransactionTests_Metropolis_ttTransactionTest, "TransactionTests/Metropolis/ttTransactionTest"} +declare_test!{TransactionTests_Metropolis_ttTransactionTestZeroSig, "TransactionTests/Metropolis/ttTransactionTestZeroSig"} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 8f9ed2e5f..980bdd25c 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -170,3 +170,4 @@ mod json_tests; pub use types::*; pub use executive::contract_address; +pub use evm::CreateContractAddress; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 0347e984f..286a89bc1 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1048,7 +1048,7 @@ impl MinerService for Miner { Action::Call(_) => None, Action::Create => { let sender = tx.sender(); - Some(contract_address(&sender, &tx.nonce)) + Some(contract_address(self.engine.schedule(pending.header().number()).create_address, &sender, &tx.nonce, &tx.data.sha3())) } }, logs: receipt.logs.clone(), @@ -1327,6 +1327,10 @@ mod tests { } fn transaction() -> SignedTransaction { + transaction_with_network_id(2) + } + + fn transaction_with_network_id(id: u64) -> SignedTransaction { let keypair = Random.generate().unwrap(); Transaction { action: Action::Create, @@ -1335,7 +1339,7 @@ mod tests { gas: U256::from(100_000), gas_price: U256::zero(), nonce: U256::zero(), - }.sign(keypair.secret(), None) + }.sign(keypair.secret(), Some(id)) } #[test] @@ -1411,18 +1415,19 @@ mod tests { #[test] fn internal_seals_without_work() { - let miner = Miner::with_spec(&Spec::new_instant()); + let spec = Spec::new_instant(); + let miner = Miner::with_spec(&spec); let client = generate_dummy_client(2); - assert_eq!(miner.import_external_transactions(&*client, vec![transaction().into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); + assert_eq!(miner.import_external_transactions(&*client, vec![transaction_with_network_id(spec.network_id()).into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); miner.update_sealing(&*client); client.flush_queue(); assert!(miner.pending_block().is_none()); assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber); - assert_eq!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction().into(), None)).unwrap(), TransactionImportResult::Current); + assert_eq!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction_with_network_id(spec.network_id()).into(), None)).unwrap(), TransactionImportResult::Current); miner.update_sealing(&*client); client.flush_queue(); diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 35f1ca983..c258d89cb 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -57,6 +57,8 @@ pub struct CommonParams { pub eip98_transition: BlockNumber, /// Validate block receipts root. pub validate_receipts_transition: u64, + /// Number of first block where EIP-86 (Metropolis) rules begin. + pub eip86_transition: BlockNumber, } impl From for CommonParams { @@ -71,6 +73,7 @@ impl From for CommonParams { fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None }, eip98_transition: p.eip98_transition.map_or(0, Into::into), validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into), + eip86_transition: p.eip86_transition.map_or(BlockNumber::max_value(), Into::into), } } } @@ -306,6 +309,7 @@ impl Spec { call_type: CallType::None, }; let mut substate = Substate::new(); + state.kill_account(address); { let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref(), &factories.vm); if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) { @@ -391,6 +395,7 @@ mod tests { #[test] fn genesis_constructor() { + ::ethcore_logger::init_log(); let spec = Spec::new_test_constructor(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let state = State::from_existing(db.boxed_clone(), spec.state_root(), spec.engine.account_start_nonce(), Default::default()).unwrap(); diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 12d7718cc..639fac053 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -1279,7 +1279,7 @@ mod tests { info.number = 0x789b0; let engine = &*Spec::new_test().engine; - println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); + println!("schedule.have_delegate_call: {:?}", engine.schedule(info.number).have_delegate_call); let t = Transaction { nonce: 0.into(), diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 6f0d7bc26..755c9f3ef 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -162,7 +162,7 @@ fn returns_logs_with_limit() { to_block: BlockId::Latest, address: None, topics: vec![], - limit: Some(2), + limit: None, }); assert_eq!(logs.len(), 0); } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 1391c37f4..548187e48 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -27,7 +27,6 @@ use builtin::Builtin; use state::*; use evm::Schedule; use engines::Engine; -use env_info::EnvInfo; use ethereum; use ethereum::ethash::EthashParams; use miner::Miner; @@ -72,7 +71,7 @@ impl Engine for TestEngine { self.engine.builtins() } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { + fn schedule(&self, _block_number: u64) -> Schedule { let mut schedule = Schedule::new_frontier(); schedule.max_depth = self.max_depth; schedule @@ -201,7 +200,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(get_test_spec: F, ac action: Action::Create, data: vec![], value: U256::zero(), - }.sign(kp.secret(), None), None).unwrap(); + }.sign(kp.secret(), Some(test_spec.network_id())), None).unwrap(); n += 1; } diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 79e27d97d..f9e9f2c47 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -19,13 +19,16 @@ use std::ops::Deref; use rlp::*; use util::sha3::Hashable; -use util::{H256, Address, U256, Bytes, HeapSizeOf}; +use util::{H256, Address, U256, Bytes, HeapSizeOf, Uint}; use ethkey::{Signature, Secret, Public, recover, public_to_address, Error as EthkeyError}; use error::*; use evm::Schedule; use header::BlockNumber; use ethjson; +/// Fake address for unsigned transactions as defined by EIP-86. +pub const UNSIGNED_SENDER: Address = ::util::H160([0xff; 20]); + #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "ipc", binary)] /// Transaction action type. @@ -110,8 +113,8 @@ impl HeapSizeOf for Transaction { impl From for SignedTransaction { fn from(t: ethjson::state::Transaction) -> Self { let to: Option = t.to.into(); - let secret = Secret::from_slice(&t.secret.0).expect("Valid secret expected."); - Transaction { + let secret = t.secret.map(|s| Secret::from_slice(&s.0).expect("Valid secret expected.")); + let tx = Transaction { nonce: t.nonce.into(), gas_price: t.gas_price.into(), gas: t.gas_limit.into(), @@ -121,7 +124,11 @@ impl From for SignedTransaction { }, value: t.value.into(), data: t.data.into(), - }.sign(&secret, None) + }; + match secret { + Some(s) => tx.sign(&s, None), + None => tx.null_sign(), + } } } @@ -180,8 +187,8 @@ impl Transaction { pub fn invalid_sign(self) -> UnverifiedTransaction { UnverifiedTransaction { unsigned: self, - r: U256::default(), - s: U256::default(), + r: U256::one(), + s: U256::one(), v: 0, hash: 0.into(), }.compute_hash() @@ -192,13 +199,28 @@ impl Transaction { SignedTransaction { transaction: UnverifiedTransaction { unsigned: self, - r: U256::default(), - s: U256::default(), + r: U256::one(), + s: U256::one(), v: 0, hash: 0.into(), }.compute_hash(), sender: from, - public: Public::default(), + public: None, + } + } + + /// Add EIP-86 compatible empty signature. + pub fn null_sign(self) -> SignedTransaction { + SignedTransaction { + transaction: UnverifiedTransaction { + unsigned: self, + r: U256::zero(), + s: U256::zero(), + v: 0, + hash: 0.into(), + }.compute_hash(), + sender: UNSIGNED_SENDER, + public: None, } } @@ -276,6 +298,11 @@ impl UnverifiedTransaction { self } + /// Checks is signature is empty. + pub fn is_unsigned(&self) -> bool { + self.r.is_zero() && self.s.is_zero() + } + /// Append object with a signature into RLP stream fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { s.begin_list(9); @@ -307,6 +334,7 @@ impl UnverifiedTransaction { /// The network ID, or `None` if this is a global transaction. pub fn network_id(&self) -> Option { match self.v { + v if self.is_unsigned() => Some(v), v if v > 36 => Some((v - 35) / 2), _ => None, } @@ -340,21 +368,33 @@ impl UnverifiedTransaction { // TODO: consider use in block validation. #[cfg(test)] #[cfg(feature = "json-tests")] - pub fn validate(self, schedule: &Schedule, require_low: bool, allow_network_id_of_one: bool) -> Result { - if require_low && !self.signature().is_low_s() { + pub fn validate(self, schedule: &Schedule, require_low: bool, allow_network_id_of_one: bool, allow_empty_signature: bool) -> Result { + let chain_id = if allow_network_id_of_one { Some(1) } else { None }; + self.verify_basic(require_low, chain_id, allow_empty_signature)?; + if !allow_empty_signature || !self.is_unsigned() { + self.recover_public()?; + } + if self.gas < U256::from(self.gas_required(&schedule)) { + return Err(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into()) + } + Ok(self) + } + + /// Verify basic signature params. Does not attempt sender recovery. + pub fn verify_basic(&self, check_low_s: bool, chain_id: Option, allow_empty_signature: bool) -> Result<(), Error> { + if check_low_s && !(allow_empty_signature && self.is_unsigned()) { + self.check_low_s()?; + } + // EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0. + if allow_empty_signature && self.is_unsigned() && !(self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero()) { return Err(EthkeyError::InvalidSignature.into()) } - match self.network_id() { - None => {}, - Some(1) if allow_network_id_of_one => {}, + match (self.network_id(), chain_id) { + (None, _) => {}, + (Some(n), Some(m)) if n == m => {}, _ => return Err(TransactionError::InvalidNetworkId.into()), - } - self.recover_public()?; - if self.gas < U256::from(self.gas_required(&schedule)) { - Err(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into()) - } else { - Ok(self) - } + }; + Ok(()) } } @@ -363,7 +403,7 @@ impl UnverifiedTransaction { pub struct SignedTransaction { transaction: UnverifiedTransaction, sender: Address, - public: Public, + public: Option, } impl HeapSizeOf for SignedTransaction { @@ -392,13 +432,21 @@ impl From for UnverifiedTransaction { impl SignedTransaction { /// Try to verify transaction and recover sender. pub fn new(transaction: UnverifiedTransaction) -> Result { - let public = transaction.recover_public()?; - let sender = public_to_address(&public); - Ok(SignedTransaction { - transaction: transaction, - sender: sender, - public: public, - }) + if transaction.is_unsigned() { + Ok(SignedTransaction { + transaction: transaction, + sender: UNSIGNED_SENDER, + public: None, + }) + } else { + let public = transaction.recover_public()?; + let sender = public_to_address(&public); + Ok(SignedTransaction { + transaction: transaction, + sender: sender, + public: Some(public), + }) + } } /// Returns transaction sender. @@ -407,9 +455,14 @@ impl SignedTransaction { } /// Returns a public key of the sender. - pub fn public_key(&self) -> Public { + pub fn public_key(&self) -> Option { self.public } + + /// Checks is signature is empty. + pub fn is_unsigned(&self) -> bool { + self.transaction.is_unsigned() + } } /// Signed Transaction that is a part of canon blockchain. @@ -435,6 +488,9 @@ impl LocalizedTransaction { if let Some(sender) = self.cached_sender { return sender; } + if self.is_unsigned() { + return UNSIGNED_SENDER.clone(); + } let sender = public_to_address(&self.recover_public() .expect("LocalizedTransaction is always constructed from transaction from blockchain; Blockchain only stores verified transactions; qed")); self.cached_sender = Some(sender); diff --git a/evmbin/src/ext.rs b/evmbin/src/ext.rs index a293ccc80..781120c36 100644 --- a/evmbin/src/ext.rs +++ b/evmbin/src/ext.rs @@ -20,7 +20,7 @@ use std::sync::Arc; use std::collections::HashMap; use util::{U256, H256, Address, Bytes, trie}; use ethcore::client::EnvInfo; -use ethcore::evm::{self, Ext, ContractCreateResult, MessageCallResult, Schedule, CallType}; +use ethcore::evm::{self, Ext, ContractCreateResult, MessageCallResult, Schedule, CallType, CreateContractAddress}; pub struct FakeExt { schedule: Schedule, @@ -31,7 +31,7 @@ pub struct FakeExt { impl Default for FakeExt { fn default() -> Self { FakeExt { - schedule: Schedule::new_post_eip150(usize::max_value(), true, true, true), + schedule: Schedule::new_post_eip150(usize::max_value(), true, true, true, true), store: HashMap::new(), depth: 1, } @@ -68,7 +68,7 @@ impl Ext for FakeExt { unimplemented!(); } - fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8]) -> ContractCreateResult { + fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8], _address: CreateContractAddress) -> ContractCreateResult { unimplemented!(); } diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index aa2c15da4..31b5cf68a 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -56,6 +56,9 @@ pub struct Params { /// See `CommonParams` docs. #[serde(rename="validateReceiptsTransition")] pub validate_receipts_transition: Option, + /// See `CommonParams` docs. + #[serde(rename="eip86Transition")] + pub eip86_transition: Option, } #[cfg(test)] diff --git a/json/src/state/test.rs b/json/src/state/test.rs index 5cc2b5f4f..ceaccfd17 100644 --- a/json/src/state/test.rs +++ b/json/src/state/test.rs @@ -75,7 +75,7 @@ pub struct MultiTransaction { pub nonce: Uint, /// Secret key. #[serde(rename="secretKey")] - pub secret: H256, + pub secret: Option, /// To. pub to: MaybeEmpty
, /// Value set. diff --git a/json/src/state/transaction.rs b/json/src/state/transaction.rs index 608be68fe..606c40f21 100644 --- a/json/src/state/transaction.rs +++ b/json/src/state/transaction.rs @@ -36,7 +36,7 @@ pub struct Transaction { pub nonce: Uint, /// Secret key. #[serde(rename="secretKey")] - pub secret: H256, + pub secret: Option, /// To. pub to: MaybeEmpty
, /// Value. diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 15fe660b2..7643e0010 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -395,6 +395,7 @@ impl Dependencies for LightDependencies { false => None, }; handler.extend_with(light::ParityClient::new( + self.client.clone(), Arc::new(dispatcher.clone()), self.secret_store.clone(), self.logger.clone(), diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index bce460350..17835485c 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -103,6 +103,7 @@ pub struct EthClient where external_miner: Arc, seed_compute: Mutex, options: EthClientOptions, + eip86_transition: u64, } impl EthClient where @@ -131,6 +132,7 @@ impl EthClient where external_miner: em.clone(), seed_compute: Mutex::new(SeedHashCompute::new()), options: options, + eip86_transition: client.eip86_transition(), } } @@ -166,7 +168,7 @@ impl EthClient where seal_fields: view.seal().into_iter().map(Into::into).collect(), uncles: block.uncle_hashes().into_iter().map(Into::into).collect(), transactions: match include_txs { - true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(Into::into).collect()), + true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t, self.eip86_transition)).collect()), false => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()), }, extra_data: Bytes::new(view.extra_data()), @@ -180,7 +182,7 @@ impl EthClient where fn transaction(&self, id: TransactionId) -> Result, Error> { match take_weak!(self.client).transaction(id) { - Some(t) => Ok(Some(Transaction::from(t))), + Some(t) => Ok(Some(Transaction::from_localized(t, self.eip86_transition))), None => Ok(None), } } @@ -507,7 +509,8 @@ impl Eth for EthClient where let hash: H256 = hash.into(); let miner = take_weak!(self.miner); let client = take_weak!(self.client); - Ok(self.transaction(TransactionId::Hash(hash))?.or_else(|| miner.transaction(client.chain_info().best_block_number, &hash).map(Into::into))) + let block_number = client.chain_info().best_block_number; + Ok(self.transaction(TransactionId::Hash(hash))?.or_else(|| miner.transaction(block_number, &hash).map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)))) } fn transaction_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> Result, Error> { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index bd55f8c63..e45397f7d 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -25,7 +25,7 @@ use jsonrpc_core::Error; use jsonrpc_macros::Trailing; use light::cache::Cache as LightDataCache; -use light::client::Client as LightClient; +use light::client::{Client as LightClient, LightChainClient}; use light::{cht, TransactionQueue}; use light::on_demand::{request, OnDemand}; @@ -123,6 +123,7 @@ impl EthClient { fn rich_block(&self, id: BlockId, include_txs: bool) -> BoxFuture, Error> { let (on_demand, sync) = (self.on_demand.clone(), self.sync.clone()); let (client, engine) = (self.client.clone(), self.client.engine().clone()); + let eip86_transition = self.client.eip86_transition(); // helper for filling out a rich block once we've got a block and a score. let fill_rich = move |block: encoded::Block, score: Option| { @@ -149,8 +150,8 @@ impl EthClient { seal_fields: header.seal().into_iter().cloned().map(Into::into).collect(), uncles: block.uncle_hashes().into_iter().map(Into::into).collect(), transactions: match include_txs { - true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(Into::into).collect()), - false => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()), + true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t, eip86_transition)).collect()), + _ => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()), }, extra_data: Bytes::new(header.extra_data().to_vec()), }, diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 96fdb61de..cacf33db5 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -28,6 +28,8 @@ use ethstore::random_phrase; use ethsync::LightSyncProvider; use ethcore::account_provider::AccountProvider; +use light::client::LightChainClient; + use jsonrpc_core::Error; use jsonrpc_macros::Trailing; use v1::helpers::{errors, ipfs, SigningQueue, SignerService, NetworkSettings}; @@ -53,11 +55,13 @@ pub struct ParityClient { signer: Option>, dapps_interface: Option, dapps_port: Option, + eip86_transition: u64, } impl ParityClient { /// Creates new `ParityClient`. pub fn new( + client: Arc, light_dispatch: Arc, accounts: Arc, logger: Arc, @@ -74,6 +78,7 @@ impl ParityClient { signer: signer, dapps_interface: dapps_interface, dapps_port: dapps_port, + eip86_transition: client.eip86_transition(), } } @@ -245,7 +250,7 @@ impl Parity for ParityClient { Ok( txq.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) .into_iter() - .map(Into::into) + .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) .collect::>() ) } @@ -256,7 +261,7 @@ impl Parity for ParityClient { Ok( txq.future_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) .into_iter() - .map(Into::into) + .map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition)) .collect::>() ) } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 78592a91c..1b62b7f81 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -69,6 +69,7 @@ pub struct ParityClient where signer: Option>, dapps_interface: Option, dapps_port: Option, + eip86_transition: u64, } impl ParityClient where @@ -103,6 +104,7 @@ impl ParityClient where signer: signer, dapps_interface: dapps_interface, dapps_port: dapps_port, + eip86_transition: client.eip86_transition(), } } @@ -288,11 +290,13 @@ impl Parity for ParityClient where } fn pending_transactions(&self) -> Result, Error> { - Ok(take_weak!(self.miner).pending_transactions().into_iter().map(Into::into).collect::>()) + let block_number = take_weak!(self.client).chain_info().best_block_number; + Ok(take_weak!(self.miner).pending_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::>()) } fn future_transactions(&self) -> Result, Error> { - Ok(take_weak!(self.miner).future_transactions().into_iter().map(Into::into).collect::>()) + let block_number = take_weak!(self.client).chain_info().best_block_number; + Ok(take_weak!(self.miner).future_transactions().into_iter().map(|t| Transaction::from_pending(t, block_number, self.eip86_transition)).collect::>()) } fn pending_transactions_stats(&self) -> Result, Error> { @@ -305,9 +309,10 @@ impl Parity for ParityClient where fn local_transactions(&self) -> Result, Error> { let transactions = take_weak!(self.miner).local_transactions(); + let block_number = take_weak!(self.client).chain_info().best_block_number; Ok(transactions .into_iter() - .map(|(hash, status)| (hash.into(), status.into())) + .map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status, block_number, self.eip86_transition))) .collect() ) } diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 19483635c..7bd8bcb91 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -39,9 +39,12 @@ pub struct ParitySetClient { updater: Weak, net: Weak, fetch: F, + eip86_transition: u64, } -impl ParitySetClient { +impl ParitySetClient + where C: MiningBlockChainClient + 'static, +{ /// Creates new `ParitySetClient` with given `Fetch`. pub fn new(client: &Arc, miner: &Arc, updater: &Arc, net: &Arc, fetch: F) -> Self { ParitySetClient { @@ -50,6 +53,7 @@ impl ParitySetClient { updater: Arc::downgrade(updater), net: Arc::downgrade(net), fetch: fetch, + eip86_transition: client.eip86_transition(), } } } @@ -175,8 +179,9 @@ impl ParitySet for ParitySetClient where fn remove_transaction(&self, hash: H256) -> Result, Error> { let miner = take_weak!(self.miner); let client = take_weak!(self.client); + let block_number = take_weak!(self.client).chain_info().best_block_number; let hash = hash.into(); - Ok(miner.remove_pending_transaction(&*client, &hash).map(Into::into)) + Ok(miner.remove_pending_transaction(&*client, &hash).map(|t| Transaction::from_pending(t, block_number, self.eip86_transition))) } } diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index 65d69775a..4383ee560 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -227,7 +227,7 @@ fn rpc_parity_remove_transaction() { let hash = signed.hash(); let request = r#"{"jsonrpc": "2.0", "method": "parity_removeTransaction", "params":[""#.to_owned() + &format!("0x{:?}", hash) + r#""], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0x0072c69d780cdfbfc02fed5c7d184151f9a166971d045e55e27695aaa5bcb55e","input":"0x","networkId":null,"nonce":"0x1","publicKey":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","r":"0x0","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80808080","s":"0x0","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","networkId":null,"nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#; miner.pending_transactions.lock().insert(hash, signed); assert_eq!(io.handle_request_sync(&request), Some(response.to_owned())); diff --git a/rpc/src/v1/tests/mocked/signing.rs b/rpc/src/v1/tests/mocked/signing.rs index 70b163023..9307d95b6 100644 --- a/rpc/src/v1/tests/mocked/signing.rs +++ b/rpc/src/v1/tests/mocked/signing.rs @@ -304,7 +304,7 @@ fn should_add_sign_transaction_to_the_queue() { r#""input":"0x","# + &format!("\"networkId\":{},", t.network_id().map_or("null".to_owned(), |n| format!("{}", n))) + r#""nonce":"0x1","# + - &format!("\"publicKey\":\"0x{:?}\",", t.public_key()) + + &format!("\"publicKey\":\"0x{:?}\",", t.public_key().unwrap()) + &format!("\"r\":\"0x{}\",", U256::from(signature.r()).to_hex()) + &format!("\"raw\":\"0x{}\",", rlp.to_hex()) + &format!("\"s\":\"0x{}\",", U256::from(signature.s()).to_hex()) + diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index b40dec3fb..e8cd1602f 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -16,8 +16,9 @@ use serde::{Serialize, Serializer}; use serde::ser::SerializeStruct; +use util::Hashable; use ethcore::miner; -use ethcore::contract_address; +use ethcore::{contract_address, CreateContractAddress}; use ethcore::transaction::{LocalizedTransaction, Action, PendingTransaction, SignedTransaction}; use v1::helpers::errors; use v1::types::{Bytes, H160, H256, U256, H512, TransactionCondition}; @@ -158,9 +159,11 @@ pub struct RichRawTransaction { pub transaction: Transaction } + impl From for RichRawTransaction { fn from(t: SignedTransaction) -> Self { - let tx: Transaction = t.into(); + // TODO: change transition to 0 when EIP-86 is commonly used. + let tx: Transaction = Transaction::from_signed(t, 0, u64::max_value()); RichRawTransaction { raw: tx.raw.clone(), transaction: tx, @@ -168,9 +171,11 @@ impl From for RichRawTransaction { } } -impl From for Transaction { - fn from(mut t: LocalizedTransaction) -> Transaction { +impl Transaction { + /// Convert `LocalizedTransaction` into RPC Transaction. + pub fn from_localized(mut t: LocalizedTransaction, eip86_transition: u64) -> Transaction { let signature = t.signature(); + let scheme = if t.block_number >= eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }; Transaction { hash: t.hash().into(), nonce: t.nonce.into(), @@ -187,7 +192,7 @@ impl From for Transaction { gas: t.gas.into(), input: Bytes::new(t.data.clone()), creates: match t.action { - Action::Create => Some(contract_address(&t.sender(), &t.nonce).into()), + Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data.sha3()).into()), Action::Call(_) => None, }, raw: ::rlp::encode(&t.signed).to_vec().into(), @@ -200,11 +205,11 @@ impl From for Transaction { condition: None, } } -} -impl From for Transaction { - fn from(t: SignedTransaction) -> Transaction { + /// Convert `SignedTransaction` into RPC Transaction. + pub fn from_signed(t: SignedTransaction, block_number: u64, eip86_transition: u64) -> Transaction { let signature = t.signature(); + let scheme = if block_number >= eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }; Transaction { hash: t.hash().into(), nonce: t.nonce.into(), @@ -221,11 +226,11 @@ impl From for Transaction { gas: t.gas.into(), input: Bytes::new(t.data.clone()), creates: match t.action { - Action::Create => Some(contract_address(&t.sender(), &t.nonce).into()), + Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data.sha3()).into()), Action::Call(_) => None, }, raw: ::rlp::encode(&t).to_vec().into(), - public_key: Some(t.public_key().into()), + public_key: t.public_key().map(Into::into), network_id: t.network_id(), standard_v: t.standard_v().into(), v: t.original_v().into(), @@ -234,28 +239,28 @@ impl From for Transaction { condition: None, } } -} -impl From for Transaction { - fn from(t: PendingTransaction) -> Transaction { - let mut r = Transaction::from(t.transaction); + /// Convert `PendingTransaction` into RPC Transaction. + pub fn from_pending(t: PendingTransaction, block_number: u64, eip86_transition: u64) -> Transaction { + let mut r = Transaction::from_signed(t.transaction, block_number, eip86_transition); r.condition = t.condition.map(|b| b.into()); r } } -impl From for LocalTransactionStatus { - fn from(s: miner::LocalTransactionStatus) -> Self { +impl LocalTransactionStatus { + /// Convert `LocalTransactionStatus` into RPC `LocalTransactionStatus`. + pub fn from(s: miner::LocalTransactionStatus, block_number: u64, eip86_transition: u64) -> Self { use ethcore::miner::LocalTransactionStatus::*; match s { Pending => LocalTransactionStatus::Pending, Future => LocalTransactionStatus::Future, - Mined(tx) => LocalTransactionStatus::Mined(tx.into()), - Dropped(tx) => LocalTransactionStatus::Dropped(tx.into()), - Rejected(tx, err) => LocalTransactionStatus::Rejected(tx.into(), errors::transaction_message(err)), - Replaced(tx, gas_price, hash) => LocalTransactionStatus::Replaced(tx.into(), gas_price.into(), hash.into()), - Invalid(tx) => LocalTransactionStatus::Invalid(tx.into()), - Canceled(tx) => LocalTransactionStatus::Canceled(tx.into()), + Mined(tx) => LocalTransactionStatus::Mined(Transaction::from_signed(tx, block_number, eip86_transition)), + Dropped(tx) => LocalTransactionStatus::Dropped(Transaction::from_signed(tx, block_number, eip86_transition)), + Rejected(tx, err) => LocalTransactionStatus::Rejected(Transaction::from_signed(tx, block_number, eip86_transition), errors::transaction_message(err)), + Replaced(tx, gas_price, hash) => LocalTransactionStatus::Replaced(Transaction::from_signed(tx, block_number, eip86_transition), gas_price.into(), hash.into()), + Invalid(tx) => LocalTransactionStatus::Invalid(Transaction::from_signed(tx, block_number, eip86_transition)), + Canceled(tx) => LocalTransactionStatus::Canceled(Transaction::from_pending(tx, block_number, eip86_transition)), } } } diff --git a/sync/src/tests/consensus.rs b/sync/src/tests/consensus.rs index 00a7452c4..6b91b11c6 100644 --- a/sync/src/tests/consensus.rs +++ b/sync/src/tests/consensus.rs @@ -41,7 +41,7 @@ impl IoHandler for TestIoHandler { } } -fn new_tx(secret: &Secret, nonce: U256) -> PendingTransaction { +fn new_tx(secret: &Secret, nonce: U256, network_id: u64) -> PendingTransaction { let signed = Transaction { nonce: nonce.into(), gas_price: 0.into(), @@ -49,7 +49,7 @@ fn new_tx(secret: &Secret, nonce: U256) -> PendingTransaction { action: Action::Call(Address::default()), value: 0.into(), data: Vec::new(), - }.sign(secret, None); + }.sign(secret, Some(network_id)); PendingTransaction::new(signed, None) } @@ -61,6 +61,7 @@ fn authority_round() { ap.insert_account(s0.secret().clone(), "").unwrap(); ap.insert_account(s1.secret().clone(), "").unwrap(); + let network_id = Spec::new_test_round().network_id(); let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_round, Some(ap)); let io_handler0: Arc> = Arc::new(TestIoHandler { client: net.peer(0).chain.clone() }); let io_handler1: Arc> = Arc::new(TestIoHandler { client: net.peer(1).chain.clone() }); @@ -74,15 +75,15 @@ fn authority_round() { // exchange statuses net.sync(); // Trigger block proposal - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into())).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into())).unwrap(); + net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), network_id)).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), network_id)).unwrap(); // Sync a block net.sync(); assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into())).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into())).unwrap(); + net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), network_id)).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), network_id)).unwrap(); // Move to next proposer step. net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); @@ -91,8 +92,8 @@ fn authority_round() { assert_eq!(net.peer(1).chain.chain_info().best_block_number, 2); // Fork the network with equal height. - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into())).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into())).unwrap(); + net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), network_id)).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), network_id)).unwrap(); // Let both nodes build one block. net.peer(0).chain.engine().step(); let early_hash = net.peer(0).chain.chain_info().best_block_hash; @@ -114,8 +115,8 @@ fn authority_round() { assert_eq!(ci1.best_block_hash, early_hash); // Selfish miner - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 3.into())).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 3.into())).unwrap(); + net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 3.into(), network_id)).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 3.into(), network_id)).unwrap(); // Node 0 is an earlier primary. net.peer(0).chain.engine().step(); assert_eq!(net.peer(0).chain.chain_info().best_block_number, 4); @@ -126,7 +127,7 @@ fn authority_round() { // Node 1 makes 2 blocks, but is a later primary on the first one. net.peer(1).chain.engine().step(); net.peer(1).chain.engine().step(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 4.into())).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 4.into(), network_id)).unwrap(); net.peer(1).chain.engine().step(); net.peer(1).chain.engine().step(); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 5); @@ -147,6 +148,7 @@ fn tendermint() { ap.insert_account(s0.secret().clone(), "").unwrap(); ap.insert_account(s1.secret().clone(), "").unwrap(); + let network_id = Spec::new_test_tendermint().network_id(); let mut net = TestNet::with_spec_and_accounts(2, SyncConfig::default(), Spec::new_test_tendermint, Some(ap)); let io_handler0: Arc> = Arc::new(TestIoHandler { client: net.peer(0).chain.clone() }); let io_handler1: Arc> = Arc::new(TestIoHandler { client: net.peer(1).chain.clone() }); @@ -162,7 +164,7 @@ fn tendermint() { // Exhange statuses net.sync(); // Propose - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into())).unwrap(); + net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 0.into(), network_id)).unwrap(); net.sync(); // Propose timeout, synchronous for now net.peer(0).chain.engine().step(); @@ -173,7 +175,7 @@ fn tendermint() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 1); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 1); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into())).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 0.into(), network_id)).unwrap(); // Commit timeout net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); @@ -187,8 +189,8 @@ fn tendermint() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 2); assert_eq!(net.peer(1).chain.chain_info().best_block_number, 2); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into())).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into())).unwrap(); + net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 1.into(), network_id)).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 1.into(), network_id)).unwrap(); // Peers get disconnected. // Commit net.peer(0).chain.engine().step(); @@ -196,8 +198,8 @@ fn tendermint() { // Propose net.peer(0).chain.engine().step(); net.peer(1).chain.engine().step(); - net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into())).unwrap(); - net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into())).unwrap(); + net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into(), network_id)).unwrap(); + net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into(), network_id)).unwrap(); // Send different prevotes net.sync(); // Prevote timeout From e83de5cde2100647f90e8965103e6f5747a07b9b Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 19 Apr 2017 15:15:43 +0200 Subject: [PATCH 21/29] Store the pending requests per network version (#5405) * Store the requests in LS per network version * Fixing tests * Add network switching test * Fixes --- js/src/redux/providers/requestsActions.js | 11 +++++- js/src/views/Application/Requests/requests.js | 2 +- .../Application/Requests/savedRequests.js | 37 +++++++++++++++++-- .../Requests/savedRequests.spec.js | 25 +++++++++++-- 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/js/src/redux/providers/requestsActions.js b/js/src/redux/providers/requestsActions.js index d31f0d1b3..970bcba91 100644 --- a/js/src/redux/providers/requestsActions.js +++ b/js/src/redux/providers/requestsActions.js @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import BigNumber from 'bignumber.js'; + import { outTransaction } from '~/api/format/output'; import { trackRequest as trackRequestUtil, parseTransactionReceipt } from '~/util/tx'; import SavedRequests from '~/views/Application/Requests/savedRequests'; @@ -29,7 +31,7 @@ export const init = (api) => (dispatch) => { dispatch(watchRequest(request)); }); - api.on('connected', () => { + api.once('connected', () => { savedRequests.load(api).then((requests) => { requests.forEach((request) => dispatch(watchRequest(request))); }); @@ -48,7 +50,9 @@ export const watchRequest = (request) => (dispatch, getState) => { export const trackRequest = (requestId, { transactionHash = null } = {}) => (dispatch, getState) => { const { api } = getState(); - trackRequestUtil(api, { requestId, transactionHash }, (error, data) => { + trackRequestUtil(api, { requestId, transactionHash }, (error, _data = {}) => { + const data = { ..._data }; + if (error) { console.error(error); return dispatch(setRequest(requestId, { error })); @@ -61,6 +65,9 @@ export const trackRequest = (requestId, { transactionHash = null } = {}) => (dis const requestData = requests[requestId]; let blockSubscriptionId = -1; + // Set the block height to 0 at the beggining + data.blockHeight = new BigNumber(0); + // If the request was a contract deployment, // then add the contract with the saved metadata to the account if (requestData.metadata && requestData.metadata.deployment) { diff --git a/js/src/views/Application/Requests/requests.js b/js/src/views/Application/Requests/requests.js index 2c2224ea0..1054cc4e2 100644 --- a/js/src/views/Application/Requests/requests.js +++ b/js/src/views/Application/Requests/requests.js @@ -145,7 +145,7 @@ class Requests extends Component { />
diff --git a/js/src/views/Application/Requests/savedRequests.js b/js/src/views/Application/Requests/savedRequests.js index ee5f78811..54f1a7a9a 100644 --- a/js/src/views/Application/Requests/savedRequests.js +++ b/js/src/views/Application/Requests/savedRequests.js @@ -21,9 +21,28 @@ import { ERROR_CODES } from '~/api/transport/error'; export const LS_REQUESTS_KEY = '_parity::requests'; export default class SavedRequests { - load (api) { - const requests = this._get(); + network = null; + /** + * Load the network version, and then the related requests + */ + load (api) { + return api.net.version() + .then((network) => { + this.network = network; + return this.loadRequests(api); + }) + .catch((error) => { + console.error(error); + return []; + }); + } + + /** + * Load the requests of the current network + */ + loadRequests (api) { + const requests = this._get(); const promises = Object.values(requests).map((request) => { const { requestId, transactionHash } = request; @@ -67,11 +86,21 @@ export default class SavedRequests { } _get () { - return store.get(LS_REQUESTS_KEY) || {}; + const allRequests = store.get(LS_REQUESTS_KEY) || {}; + + return allRequests[this.network] || {}; } _set (requests = {}) { - return store.set(LS_REQUESTS_KEY, requests); + const allRequests = store.get(LS_REQUESTS_KEY) || {}; + + if (Object.keys(requests).length > 0) { + allRequests[this.network] = requests; + } else { + delete allRequests[this.network]; + } + + return store.set(LS_REQUESTS_KEY, allRequests); } _requestExists (api, requestId) { diff --git a/js/src/views/Application/Requests/savedRequests.spec.js b/js/src/views/Application/Requests/savedRequests.spec.js index 7563c93c8..acf3adc39 100644 --- a/js/src/views/Application/Requests/savedRequests.spec.js +++ b/js/src/views/Application/Requests/savedRequests.spec.js @@ -19,27 +19,37 @@ import store from 'store'; import SavedRequests, { LS_REQUESTS_KEY } from './savedRequests'; +const NETWORK_ID = 42; const DEFAULT_REQUEST = { requestId: '0x1', transaction: {} }; -const api = createApi(); +const api = createApi(NETWORK_ID); +const api2 = createApi(1); const savedRequests = new SavedRequests(); -function createApi () { +function createApi (networkVersion) { return { parity: { checkRequest: sinon.stub().resolves() + }, + net: { + version: sinon.stub().resolves(networkVersion) } }; } describe('views/Application/Requests/savedRequests', () => { - beforeEach(() => { + beforeEach((done) => { store.set(LS_REQUESTS_KEY, { - [DEFAULT_REQUEST.requestId]: DEFAULT_REQUEST + [NETWORK_ID]: { + [DEFAULT_REQUEST.requestId]: DEFAULT_REQUEST + } }); + + savedRequests.load(api) + .then(() => done()); }); afterEach(() => { @@ -85,4 +95,11 @@ describe('views/Application/Requests/savedRequests', () => { expect(requests[0]).to.deep.equal(DEFAULT_REQUEST); }); }); + + it('loads requests from the right network', () => { + return savedRequests.load(api2) + .then((requests) => { + expect(requests).to.deep.equal([]); + }); + }); }); From 8310877f257c33a574b4350161d0baf3297f8296 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Wed, 19 Apr 2017 13:42:54 +0000 Subject: [PATCH 22/29] [ci skip] js-precompiled 20170419-133906 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8208f583e..dccc2f8df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1773,7 +1773,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#fb346e5f2925d1b2d533eb986bd2cefb962c7a88" +source = "git+https://github.com/paritytech/js-precompiled.git#7b0c9ffdfa680f7792751f03d3490fc2a9fea23f" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index 4f4b33ab7..da567a458 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.53", + "version": "1.7.54", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From e1e2674cd23e5db4902eb85fcb8784e321dd2c19 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 19 Apr 2017 16:02:24 +0200 Subject: [PATCH 23/29] Show ETH value (even 0) if ETH transfert in transaction list (#5406) --- js/src/ui/TxList/TxRow/txRow.js | 37 +++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/js/src/ui/TxList/TxRow/txRow.js b/js/src/ui/TxList/TxRow/txRow.js index 8d123c13c..1fcf54396 100644 --- a/js/src/ui/TxList/TxRow/txRow.js +++ b/js/src/ui/TxList/TxRow/txRow.js @@ -21,9 +21,10 @@ import { Link } from 'react-router'; import { txLink } from '~/3rdparty/etherscan/links'; -import IdentityIcon from '../../IdentityIcon'; -import IdentityName from '../../IdentityName'; -import MethodDecoding from '../../MethodDecoding'; +import IdentityIcon from '~/ui/IdentityIcon'; +import IdentityName from '~/ui/IdentityName'; +import MethodDecoding from '~/ui/MethodDecoding'; +import MethodDecodingStore from '~/ui/MethodDecoding/methodDecodingStore'; import styles from '../txList.css'; @@ -48,6 +49,29 @@ class TxRow extends Component { historic: true }; + state = { + isContract: false, + isDeploy: false + }; + + methodDecodingStore = MethodDecodingStore.get(this.context.api); + + componentWillMount () { + const { address, tx } = this.props; + + this + .methodDecodingStore + .lookup(address, tx) + .then((lookup) => { + const newState = { + isContract: lookup.contract, + isDeploy: lookup.deploy + }; + + this.setState(newState); + }); + } + render () { const { address, className, historic, netVersion, tx } = this.props; @@ -117,9 +141,14 @@ class TxRow extends Component { renderEtherValue (_value) { const { api } = this.context; + const { isContract, isDeploy } = this.state; + + // Always show the value if ETH transfer, ie. not + // a contract or a deployment + const fullValue = !(isContract || isDeploy); const value = api.util.fromWei(_value); - if (value.eq(0)) { + if (value.eq(0) && !fullValue) { return
{ ' ' }
; } From 23e7b53c138a564e2ad7fd22432b63c34d05895c Mon Sep 17 00:00:00 2001 From: Bas Date: Wed, 19 Apr 2017 16:08:47 +0200 Subject: [PATCH 24/29] nl i18n updated (#5461) * Sync nl i18n to default * Syntax fix in nl i18n Tested locally * nl translation improvements --- js/src/i18n/nl/account.js | 6 +- js/src/i18n/nl/accounts.js | 7 ++- js/src/i18n/nl/addAddress.js | 3 +- js/src/i18n/nl/address.js | 28 +++++++++ js/src/i18n/nl/addresses.js | 25 ++++++++ js/src/i18n/nl/application.js | 3 + js/src/i18n/nl/contract.js | 24 ++++++- js/src/i18n/nl/contracts.js | 28 +++++++++ js/src/i18n/nl/createAccount.js | 28 +++++---- js/src/i18n/nl/createWallet.js | 5 +- js/src/i18n/nl/dapps.js | 3 +- js/src/i18n/nl/deployContract.js | 9 +++ js/src/i18n/nl/faucet.js | 28 +++++++++ js/src/i18n/nl/firstRun.js | 21 ++++++- js/src/i18n/nl/index.js | 22 ++++++- js/src/i18n/nl/passwordChange.js | 1 + js/src/i18n/nl/saveContract.js | 27 ++++++++ js/src/i18n/nl/settings.js | 20 ++++-- js/src/i18n/nl/signer.js | 103 +++++++++++++++++++++++++++++++ js/src/i18n/nl/status.js | 66 ++++++++++++++++++++ js/src/i18n/nl/transfer.js | 36 ++++++++++- js/src/i18n/nl/ui.js | 97 ++++++++++++++++++++++++++--- js/src/i18n/nl/upgradeParity.js | 9 ++- js/src/i18n/nl/vaults.js | 37 ++++++++++- js/src/i18n/nl/verification.js | 85 +++++++++++++++++++++++++ js/src/i18n/nl/wallet.js | 45 ++++++++++++++ js/src/i18n/nl/walletSettings.js | 26 +++++--- js/src/i18n/nl/writeContract.js | 62 +++++++++++++++++++ 28 files changed, 804 insertions(+), 50 deletions(-) create mode 100644 js/src/i18n/nl/address.js create mode 100644 js/src/i18n/nl/addresses.js create mode 100644 js/src/i18n/nl/contracts.js create mode 100644 js/src/i18n/nl/faucet.js create mode 100644 js/src/i18n/nl/saveContract.js create mode 100644 js/src/i18n/nl/signer.js create mode 100644 js/src/i18n/nl/status.js create mode 100644 js/src/i18n/nl/verification.js create mode 100644 js/src/i18n/nl/wallet.js create mode 100644 js/src/i18n/nl/writeContract.js diff --git a/js/src/i18n/nl/account.js b/js/src/i18n/nl/account.js index 57701292a..ee211bbca 100755 --- a/js/src/i18n/nl/account.js +++ b/js/src/i18n/nl/account.js @@ -16,13 +16,17 @@ export default { button: { - delete: `verwijder account`, + delete: `verwijder`, edit: `bewerk`, + faucet: `Kovan ETH`, password: `wachtwoord`, shapeshift: `shapeshift`, transfer: `verzend`, verify: `verifieer` }, + hardware: { + confirmDelete: `Weet je zeker dat je de volgende hardware adressen van je account lijst wilt verwijderen?` + }, header: { outgoingTransactions: `{count} uitgaande transacties`, uuid: `uuid: {uuid}` diff --git a/js/src/i18n/nl/accounts.js b/js/src/i18n/nl/accounts.js index 315324632..e213bddb2 100755 --- a/js/src/i18n/nl/accounts.js +++ b/js/src/i18n/nl/accounts.js @@ -16,8 +16,8 @@ export default { button: { - newAccount: `nieuw account`, - newWallet: `nieuw wallet`, + newAccount: `account`, + newWallet: `wallet`, vaults: `kluizen` }, summary: { @@ -27,5 +27,8 @@ export default { tooltip: { actions: `voor de huidige weergave zijn koppelingen beschikbaar op de werkbalk voor snelle toegang: het uitvoeren van acties of het creëren van een nieuw item`, overview: `hier vind je een overzichtelijke weergave van je accounts, waarin je meta informatie kunt bewerken en transacties kunt uitvoeren en bekijken` + }, + tooltips: { + owner: `{name} (eigenaar)` } }; diff --git a/js/src/i18n/nl/addAddress.js b/js/src/i18n/nl/addAddress.js index 1b2281888..e048988e9 100755 --- a/js/src/i18n/nl/addAddress.js +++ b/js/src/i18n/nl/addAddress.js @@ -19,6 +19,7 @@ export default { add: `Adres Opslaan`, close: `Annuleer` }, + header: `Om een nieuwe invoer aan je adresboek toe te voegen, heb je het netwerk adres van het account nodig en kun je optioneel een beschrijving toevoegen. Zodra de nieuwe invoer is toegevoegd, zal het in je adresboek verschijnen.`, input: { address: { hint: `het netwerk adres van het item`, @@ -33,5 +34,5 @@ export default { label: `Adres Naam` } }, - label: `voeg opgeslagen adres toe` + label: `voeg een opgeslagen adres toe` }; diff --git a/js/src/i18n/nl/address.js b/js/src/i18n/nl/address.js new file mode 100644 index 000000000..fc9d2eab1 --- /dev/null +++ b/js/src/i18n/nl/address.js @@ -0,0 +1,28 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + buttons: { + edit: `bewerken`, + forget: `vergeten`, + save: `opslaan` + }, + delete: { + confirmInfo: `Weet je zeker dat je het volgende adres uit je adresboek wilt verwijderen?`, + title: `bevestig verwijderen` + }, + title: `Adres Informatie` +}; diff --git a/js/src/i18n/nl/addresses.js b/js/src/i18n/nl/addresses.js new file mode 100644 index 000000000..c16c5f234 --- /dev/null +++ b/js/src/i18n/nl/addresses.js @@ -0,0 +1,25 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + buttons: { + add: `adres` + }, + errors: { + invalidFile: `Het opgegeven bestand is ongeldig...` + }, + title: `Opgeslagen Adressen` +}; diff --git a/js/src/i18n/nl/application.js b/js/src/i18n/nl/application.js index 1a6b2ee5c..bcb110b88 100755 --- a/js/src/i18n/nl/application.js +++ b/js/src/i18n/nl/application.js @@ -15,6 +15,9 @@ // along with Parity. If not, see . export default { + frame: { + error: `FOUT: Deze applicatie kan niet en zou niet geladen moeten worden in een embedded iFrame` + }, status: { consensus: { capable: `Capable`, diff --git a/js/src/i18n/nl/contract.js b/js/src/i18n/nl/contract.js index 5f2ca39cc..9818f5edd 100755 --- a/js/src/i18n/nl/contract.js +++ b/js/src/i18n/nl/contract.js @@ -15,5 +15,27 @@ // along with Parity. If not, see . export default { - minedBlock: `Opgenomen in blok #{blockNumber}` + buttons: { + close: `Sluit`, + details: `details`, + edit: `bewerken`, + execute: `uitvoeren`, + forget: `vergeten` + }, + details: { + title: `contract details` + }, + events: { + eventPending: `pending`, + noEvents: `Er zijn vanuit dit contract nog geen events verzonden.`, + title: `events` + }, + minedBlock: `Opgenomen in blok #{blockNumber}`, + queries: { + buttons: { + query: `Query` + }, + title: `queries` + }, + title: `Contract Informatie` }; diff --git a/js/src/i18n/nl/contracts.js b/js/src/i18n/nl/contracts.js new file mode 100644 index 000000000..18ab842a0 --- /dev/null +++ b/js/src/i18n/nl/contracts.js @@ -0,0 +1,28 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + buttons: { + deploy: `publiceer`, + develop: `ontwikkel`, + watch: `bekijk` + }, + sortOrder: { + date: `datum`, + minedBlock: `opgenomen blok` + }, + title: `Contracten` +}; diff --git a/js/src/i18n/nl/createAccount.js b/js/src/i18n/nl/createAccount.js index 69585df35..98b7ac26b 100755 --- a/js/src/i18n/nl/createAccount.js +++ b/js/src/i18n/nl/createAccount.js @@ -20,10 +20,6 @@ export default { hint: `Het netwerk adres van het account`, label: `adres` }, - name: { - hint: `Een beschrijvende naam van het account`, - label: `account naam` - }, phrase: { hint: `De account herstel zin`, label: `Eigenaar's herstel zin (houd deze woorden veilig en prive want hiermee kun je volledige, ongelimiteerde toegang tot het account verkrijgen).` @@ -35,31 +31,38 @@ export default { button: { back: `Terug`, cancel: `Annuleer`, - close: `Sluit`, create: `Aanmaken`, + done: `Klaar`, import: `Importeer`, next: `Volgende`, print: `Herstel zin afdrukken` }, creationType: { fromGeth: { - label: `Importeer accounts uit Geth keystore` + description: `Importeer accounts uit Geth keystore met het originele wachtwoord`, + label: `Geth keystore` }, fromJSON: { - label: `Importeer account uit een opgeslagen JSON file` + description: `Importeer account uit een JSON sleutelbestand met het originele wachtwoord`, + label: `JSON bestand` }, fromNew: { - label: `Handmatig account aanmaken` + description: `Selecteer je identiteits-icoon en kies je wachtwoord`, + label: `Nieuw Account` }, fromPhrase: { - label: `Herstel account met een herstel zin` + description: `Herstel je account met een eerder bewaarde herstel zin en een nieuw wachtwoord`, + label: `Herstel zin` }, fromPresale: { - label: `Importeer account van een Ethereum voor-verkoop (pre-sale) wallet` + description: `Importeer een Ethereum voor-verkoop (pre-sale) wallet bestand met het originele wachtwoord`, + label: `voor-verkoop wallet` }, fromRaw: { - label: `Importeer een prive sleutel (raw private key)` - } + description: `Importeer een eerder gemaakte prive sleutel (raw private key) met een nieuw wachtwoord`, + label: `Prive sleutel` + }, + info: `Selecteer de manier waarop je je account wilt aanmaken of importeren. Maak een nieuw account aan met een naam en wachtwoord, of importeer/herstel een bestaand account vanuit verschillende bronnen zoals een herstel zin of een sleutelbestand. Met behulp van deze wizard word je door het proces begeleid om een account aan te maken.` }, newAccount: { hint: { @@ -80,6 +83,7 @@ export default { } }, newGeth: { + available: `Er zijn momenteel {count} importeerbare sleutels (keys) beschikbaar vanuit Geth keystore, welke nog niet in je Parity installatie beschikbaar zijn. Selecteer de accounts die je wilt importeren en ga verder naar de volgende stap om het importeren te voltooien.`, noKeys: `Er zijn momenteel geen importeerbare sleutels (keys) beschikbaar in de Geth keystore; of ze zijn al in je Parity installatie beschikbaar` }, newImport: { diff --git a/js/src/i18n/nl/createWallet.js b/js/src/i18n/nl/createWallet.js index 6acd2e2c8..9f3419497 100644 --- a/js/src/i18n/nl/createWallet.js +++ b/js/src/i18n/nl/createWallet.js @@ -53,7 +53,7 @@ export default { label: `wallet naam` }, ownerMulti: { - hint: `het eigenaars account van dit contract`, + hint: `het account wat eigenaar is van dit contract`, label: `van account (contract eigenaar)` }, ownersMulti: { @@ -80,6 +80,7 @@ export default { }, states: { completed: `Het contract is succesvol aangemaakt`, + confirmationNeeded: `Voor het aanmaken van dit contract is bevestiging door andere eigenaren van het Wallet vereist`, preparing: `Transactie aan het voorbereiden voor verzending op het netwerk`, validatingCode: `De contract code van het aangemaakte contract wordt gevalideerd`, waitingConfirm: `Wachten tot de transactie bevestigd is in de Parity Secure Signer`, @@ -93,7 +94,7 @@ export default { }, type: { multisig: { - description: `Creëer/Maak een {link} Wallet aan`, + description: `Maak een {link} Wallet aan`, label: `Multi-Sig wallet`, link: `standaard multi-signature` }, diff --git a/js/src/i18n/nl/dapps.js b/js/src/i18n/nl/dapps.js index 3c7cf6d7b..6949c4d48 100644 --- a/js/src/i18n/nl/dapps.js +++ b/js/src/i18n/nl/dapps.js @@ -36,11 +36,10 @@ export default { }, external: { accept: `Ik begrijp dat deze toepassingen niet bij Parity zijn aangesloten`, - warning: `Deze applicaties gepuliceerd door derde partijen zijn niet bij Parity aangesloten, noch worden ze gepubliceerd door Parity. Alle applicaties blijven in beheer van hun eigen auteur. Zorg ervoor dat je snapt wat het doel van een applicatie is voordat je ermee aan de slag gaat.` + warning: `Deze applicaties zijn gepuliceerd door derde partijen welke niet verwant zijn aan Parity en zijn dus ook niet door Parity uitgebracht. Alle applicaties blijven in beheer van hun eigen auteur. Zorg ervoor dat je snapt wat het doel van een applicatie is voordat je ermee aan de slag gaat.` }, label: `Gedecentraliseerde Applicaties`, permissions: { - description: `{activeIcon} account is beschikbaar voor applicaties, {defaultIcon} account is het standaard account`, label: `zichtbare dapp accounts` } }; diff --git a/js/src/i18n/nl/deployContract.js b/js/src/i18n/nl/deployContract.js index 478992464..042d52276 100644 --- a/js/src/i18n/nl/deployContract.js +++ b/js/src/i18n/nl/deployContract.js @@ -37,6 +37,13 @@ export default { hint: `het account wat eigenaar is van dit contract`, label: `van account (contract eigenaar)` }, + advanced: { + label: `geavanceerde verzend opties` + }, + amount: { + hint: `de naar het contract te verzenden hoeveelheid`, + label: `te verzenden hoeveelheid (in {tag})` + }, code: { hint: `de gecompileerde code van het aan te maken contract`, label: `code` @@ -65,6 +72,7 @@ export default { }, state: { completed: `Het contract is succesvol aangemaakt`, + confirmationNeeded: `Deze actie vereist de bevestiging van de andere eigenaren van het contract`, preparing: `Transactie aan het voorbereiden om te verzenden op het netwerk`, validatingCode: `De contract code van het aangemaakte contract valideren`, waitReceipt: `Wachten tot het aanmaken van het contract bevestigd is`, @@ -74,6 +82,7 @@ export default { completed: `voltooid`, deployment: `aangemaakt`, details: `contract details`, + extras: `extra informatie`, failed: `aanmaken mislukt`, parameters: `contract parameters`, rejected: `afgewezen` diff --git a/js/src/i18n/nl/faucet.js b/js/src/i18n/nl/faucet.js new file mode 100644 index 000000000..f35acc0b7 --- /dev/null +++ b/js/src/i18n/nl/faucet.js @@ -0,0 +1,28 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + buttons: { + close: `sluit`, + done: `klaar`, + request: `verzoek` + }, + summary: { + done: `Jouw Kovan ETH is aangevraagd bij het faucet, wat reageerde met het volgende bericht -`, + info: `Om een hoeveelheid Kovan ETH aan te vragen voor dit adres, moet je ervoor zorgen dat het adres op het mainnet sms-geverifieerd is. Zodra je dit uitvoert, zal het faucet Kovan ETH naar je huidige account verzenden.` + }, + title: `Kovan ETH Faucet` +}; diff --git a/js/src/i18n/nl/firstRun.js b/js/src/i18n/nl/firstRun.js index d182c76e1..9c7c4cf5d 100755 --- a/js/src/i18n/nl/firstRun.js +++ b/js/src/i18n/nl/firstRun.js @@ -17,16 +17,33 @@ export default { button: { close: `Sluiten`, - create: `creëer`, - next: `volgende`, + create: `Creëer`, + next: `Volgende`, print: `Woorden Afdrukken`, skip: `Overslaan` }, + completed: { + congrats: `Gefeliciteerd! Je node configuratie is succesvol afgerond en het programma is klaar voor gebruikt.`, + next: `Om je snel aan de slag te laten gaan krijg je in de volgende stap een korte algemene inleiding in het gebruik van het programma en lopen we door de beschikbare funcies.` + }, title: { completed: `voltooid`, newAccount: `nieuw account`, recovery: `herstelzin`, terms: `voorwaarden`, welcome: `welkom` + }, + tnc: { + accept: `Ik accepteer de voorwaarden en condities` + }, + welcome: { + description: `Als onderdeel van een nieuwe installatie, begeleiden we je in de enkele hierna volgende stappen met het configureren van je Parity node en jouw bijbehorende accounts. Ons doel hiervan is om het je zo gemakkelijk mogelijk te maken and zodat je binnen de kortste tijd klaar bent voor gebruik, dus heb even geduld en blijf bij ons. Zodra je de wizard voltooid hebt, heb je -`, + greeting: `Welkom bij Parity, de snelste en makkelijkste manier om je eigen node te draaien.`, + next: `Klik volgende om door te gaan.`, + step: { + account: `Je eerste Parity account aangemaakt;`, + privacy: `Onze privacybeleid en bedrijfsvoorwaarden begrepen;`, + recovery: `De mogelijkheid om je account te herstellen.` + } } }; diff --git a/js/src/i18n/nl/index.js b/js/src/i18n/nl/index.js index 281e9974c..0d11be8f1 100755 --- a/js/src/i18n/nl/index.js +++ b/js/src/i18n/nl/index.js @@ -18,10 +18,13 @@ import account from './account'; import accounts from './accounts'; import addAddress from './addAddress'; import addContract from './addContract'; +import address from './address'; +import addresses from './addresses'; import addressSelect from './addressSelect'; import application from './application'; import connection from './connection'; import contract from './contract'; +import contracts from './contracts'; import createAccount from './createAccount'; import createWallet from './createWallet'; import dapp from './dapp'; @@ -32,31 +35,41 @@ import editMeta from './editMeta'; import errors from './errors'; import executeContract from './executeContract'; import extension from './extension'; +import faucet from './faucet'; import firstRun from './firstRun'; import home from './home'; import loadContract from './loadContract'; import parityBar from './parityBar'; import passwordChange from './passwordChange'; +import saveContract from './saveContract'; import settings from './settings'; import shapeshift from './shapeshift'; +import signer from './signer'; +import status from './status'; import tabBar from './tabBar'; import transfer from './transfer'; import txEditor from './txEditor'; import ui from './ui'; import upgradeParity from './upgradeParity'; import vaults from './vaults'; +import verification from './verification'; +import wallet from './wallet'; import walletSettings from './walletSettings'; import web from './web'; +import writeContract from './writeContract'; export default { account, accounts, addAddress, addContract, + address, + addresses, addressSelect, application, connection, contract, + contracts, createAccount, createWallet, dapp, @@ -67,19 +80,26 @@ export default { errors, executeContract, extension, + faucet, firstRun, home, loadContract, parityBar, passwordChange, + saveContract, settings, shapeshift, + signer, + status, tabBar, transfer, txEditor, ui, upgradeParity, vaults, + verification, + wallet, walletSettings, - web + web, + writeContract }; diff --git a/js/src/i18n/nl/passwordChange.js b/js/src/i18n/nl/passwordChange.js index c59e50eed..eca3fd919 100644 --- a/js/src/i18n/nl/passwordChange.js +++ b/js/src/i18n/nl/passwordChange.js @@ -30,6 +30,7 @@ export default { label: `nieuw wachtwoord` }, passwordHint: { + display: `Hint {hint}`, hint: `hint voor het nieuwe wachtwoord`, label: `(optioneel) nieuwe wachtwoord hint` }, diff --git a/js/src/i18n/nl/saveContract.js b/js/src/i18n/nl/saveContract.js new file mode 100644 index 000000000..e51a3be3d --- /dev/null +++ b/js/src/i18n/nl/saveContract.js @@ -0,0 +1,27 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + buttons: { + cancel: `Annuleer`, + save: `Opslaan` + }, + name: { + hint: `kies een naam voor dit contract`, + label: `contract naam` + }, + title: `contract opslaan` +}; diff --git a/js/src/i18n/nl/settings.js b/js/src/i18n/nl/settings.js index 81f485696..f6705df78 100644 --- a/js/src/i18n/nl/settings.js +++ b/js/src/i18n/nl/settings.js @@ -22,6 +22,18 @@ export default { label: `achtergrond` }, parity: { + chains: { + chain_classic: `Parity synchroniseert met het Ethereum Classic netwerk`, + chain_dev: `Parity gebruikt een lokale ontwikkelaars chain`, + chain_expanse: `Parity synchroniseert met het Expanse netwerk`, + chain_foundation: `Parity synchroniseert met het Ethereum netwerk wat door de Ethereum Foundation is uitgebracht`, + chain_kovan: `Parity synchroniseert met het Kovan test netwerk`, + chain_olympic: `Parity synchroniseert met het Olympic test netwerk`, + chain_ropsten: `Parity synchroniseert met het Ropsten test netwerk`, + cmorden_kovan: `Parity synchroniseert met het Morden (Classic) test netwerk`, + hint: `de chain waarmee de Parity node synchroniseert`, + label: `te synchroniseren chain/netwerk` + }, languages: { hint: `de taal waarin deze interface wordt weergegeven`, label: `Weergave taal` @@ -35,7 +47,7 @@ export default { mode_offline: `Parity synchroniseert niet`, mode_passive: `Parity synchroniseert in het begin. Daarna slaapt Parity en wordt regelmatig wakker voor synchronisatie` }, - overview_0: `Pas de Parity node instellingen aan en kies de synchronisatie modus in dit menu.`, + overview_0: `Pas de Parity node instellingen aan en kies de manier van synchroniseren in dit menu.`, label: `parity` }, proxy: { @@ -53,7 +65,7 @@ export default { label: `Accounts` }, addresses: { - description: `Een overzicht van alle contacten en adresboek items die door deze Parity installatie worden beheerd. Monitor en volg accounts waarbij je transactie details met slechts een muisklik kunt weergeven.`, + description: `Een overzicht van alle door deze Parity installatie beheerde contacten en adresboek items. Monitor en volg accounts waarbij je transactie details met slechts een muisklik kunt weergeven.`, label: `Adresboek` }, apps: { @@ -64,10 +76,10 @@ export default { description: `Monitor, volg en maak gebruik van specifieke contracten die op het netwerk zijn gezet. Dit is een meer technisch gerichte omgeving, voornamelijk bedoeld voor geavanceerde gebruikers die de werking van bepaalde contracten goed begrijpen.`, label: `Contracten` }, - overview_0: `Beheer de beschikbare weergaven van deze interface en selecteer enkel de delen van de applicatie die voor jou van belang zijn.`, + overview_0: `Beheer de beschikbare weergaven van deze interface, en selecteer enkel de delen van de applicatie die voor jou van belang zijn.`, overview_1: `Ben je een eind gebruiker? De standaard instellingen zijn geschikt voor zowel beginners als gevorderde gebruikers.`, overview_2: `Ben je een ontwikkelaar? Voeg enkele functies toe om je contracten te beheren en gebruik te maken van gedecentraliseerde applicaties.`, - overview_3: `Ben je een miner of run je een grootschalige node? Voeg enkele functies toe om je alle informatie te geven die je nodig hebt om je node te monitoren.`, + overview_3: `Ben je een miner of draai je een grootschalige node? Voeg enkele functies toe om je alle informatie te geven die je nodig hebt om je node te monitoren.`, settings: { description: `Deze weergave. Hiermee kun je Parity aan passen in termen van opties, bediening en look en feel.`, label: `Instellingen` diff --git a/js/src/i18n/nl/signer.js b/js/src/i18n/nl/signer.js new file mode 100644 index 000000000..ec7ee96f8 --- /dev/null +++ b/js/src/i18n/nl/signer.js @@ -0,0 +1,103 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + embedded: { + noPending: `Er zijn momenteel geen lopende verzoeken die op je goedkeuring wachten` + }, + mainDetails: { + editTx: `Bewerk condities/gas/gasprijs`, + tooltips: { + total1: `De waarde van de transactie inclusief de miningskosten is {total} {type}.`, + total2: `(Dit is inclusief een miners vergoeding van {fee} {token})`, + value1: `De waarde van de transactie.` + } + }, + requestOrigin: { + dapp: `door een dapp op {url}`, + ipc: `via IPC sessie`, + rpc: `via RPC {rpc}`, + signerCurrent: `via huidige tab`, + signerUI: `via UI sessie`, + unknownInterface: `via onbekende interface`, + unknownRpc: `niet geïdentificeerd`, + unknownUrl: `onbekende URL` + }, + requestsPage: { + noPending: `Er zijn geen verzoeken die je goedkeuring vereisen.`, + pendingTitle: `Openstaande Verzoeken`, + queueTitle: `Lokale Transacties` + }, + sending: { + hardware: { + confirm: `Bevestig de transactie op je aangesloten hardware wallet`, + connect: `Sluit je hardware wallet aan voordat je de transactie bevestigd` + } + }, + signRequest: { + request: `Een verzoek om data te ondertekenen met jouw account:`, + state: { + confirmed: `Bevestigd`, + rejected: `Afgewezen` + }, + unknownBinary: `(Onbekende binary data)`, + warning: `WAARSCHUWING: Deze gevolgen hiervan kunnen ernstig zijn. Bevestig het verzoek alleen als je het zeker weet.` + }, + title: `Trusted Signer`, + txPending: { + buttons: { + viewToggle: `bekijk transactie` + } + }, + txPendingConfirm: { + buttons: { + confirmBusy: `Bevestigen...`, + confirmRequest: `Bevestig Verzoek` + }, + errors: { + invalidWallet: `Opgegeven wallet bestand is ongeldig.` + }, + password: { + decrypt: { + hint: `open (decrypt) de sleutel met je wachtwoord`, + label: `Sleutel Wachtwoord` + }, + unlock: { + hint: `ontgrendel het account`, + label: `Account Wachtwoord` + } + }, + passwordHint: `(hint) {passwordHint}`, + selectKey: { + hint: `De sleutelbestand (keyfile) die je voor dit account wilt gebruiken`, + label: `Selecteer Lokale Sleutel (key)` + }, + tooltips: { + password: `Geef een wachtwoord voor dit account` + } + }, + txPendingForm: { + changedMind: `Ik heb me bedacht`, + reject: `wijs verzoek af` + }, + txPendingReject: { + buttons: { + reject: `Wijs Verzoek Af` + }, + info: `Weet je zeker dat je dit verzoek wilt afwijzen?`, + undone: `Dit kan niet ongedaan gemaakt worden` + } +}; diff --git a/js/src/i18n/nl/status.js b/js/src/i18n/nl/status.js new file mode 100644 index 000000000..9c0294ab0 --- /dev/null +++ b/js/src/i18n/nl/status.js @@ -0,0 +1,66 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + debug: { + reverse: `Omgekeerde volgorde`, + stopped: `De live weergave van de Parity logboeken is momenteel gestopt via de UI, start de live weergave om de laatste updates te zien.`, + title: `Node Logboeken` + }, + miningSettings: { + input: { + author: { + hint: `de mining auteur`, + label: `auteur` + }, + extradata: { + hint: `extra data voor mined blokken`, + label: `extra data` + }, + gasFloor: { + hint: `het gas-floor doel voor mining`, + label: `gas-floor doel` + }, + gasPrice: { + hint: `de minimale gas prijs voor mining`, + label: `minimale gas prijs` + } + }, + title: `mining instellingen` + }, + status: { + hashrate: `{hashrate} H/s`, + input: { + chain: `chain`, + enode: `enode`, + no: `nee`, + peers: `peers`, + port: `netwerk poort`, + rpcEnabled: `rpc ingeschakeld`, + rpcInterface: `rpc interface`, + rpcPort: `rpc poort`, + yes: `ja` + }, + title: { + bestBlock: `beste block`, + hashRate: `hash rate`, + network: `netwerk instellingen`, + node: `Node`, + peers: `peers` + } + }, + title: `Status` +}; diff --git a/js/src/i18n/nl/transfer.js b/js/src/i18n/nl/transfer.js index 1370711b4..29866470b 100644 --- a/js/src/i18n/nl/transfer.js +++ b/js/src/i18n/nl/transfer.js @@ -21,7 +21,41 @@ export default { label: `transactie data` } }, + buttons: { + back: `Terug`, + cancel: `Annuleer`, + close: `Sluit`, + next: `Volgende`, + send: `Verzend` + }, + details: { + advanced: { + label: `geavanceerde verzend opties` + }, + amount: { + hint: `de naar de ontvanger te verzenden hoeveelheid`, + label: `te verzenden hoeveelheid (in {tag})` + }, + fullBalance: { + label: `volledige account balans` + }, + recipient: { + hint: `het ontvangende adres`, + label: `ontvanger adres` + }, + sender: { + hint: `het verzendende adres`, + label: `Verzender adres` + }, + total: { + label: `totale transactie hoeveelheid` + } + }, + wallet: { + confirmation: `Deze transactie vereist bevestiging van andere eigenaren.`, + operationHash: `hash van deze bewerking` + }, warning: { - wallet_spent_limit: `Deze transactie waarde is boven de toegestane dag limiet en zal moeten worden bevestigd door andere eigenaren.` + wallet_spent_limit: `De waarde van deze transactie is hoger dan de toegestane dag limiet en zal moeten worden bevestigd door andere eigenaren.` } }; diff --git a/js/src/i18n/nl/ui.js b/js/src/i18n/nl/ui.js index c0454e9f6..1b7a9163b 100644 --- a/js/src/i18n/nl/ui.js +++ b/js/src/i18n/nl/ui.js @@ -15,8 +15,40 @@ // along with Parity. If not, see . export default { + actionbar: { + export: { + button: { + export: `exporteer` + } + }, + import: { + button: { + cancel: `Annuleer`, + confirm: `Bevestig`, + import: `importeer` + }, + confirm: `Bevestig dat dit is wat je wilt importeren.`, + error: `Er is een fout opgetreden: {errorText}`, + step: { + error: `fout`, + select: `selecteer een bestand`, + validate: `valideer` + }, + title: `Importeer vanuit een bestand` + }, + search: { + hint: `Voer zoekopdracht in...` + }, + sort: { + sortBy: `Sorteer op {label}`, + typeDefault: `Standaard`, + typeEth: `Sorteer op ETH`, + typeName: `Sorteer op naam`, + typeTags: `Sorteer op tags` + } + }, balance: { - none: `Er zijn geen tegoeden gekoppeld aan dit account` + none: `Geen tegoeden gekoppeld aan dit account` }, blockStatus: { bestBlock: `{blockNumber} beste blok`, @@ -28,10 +60,61 @@ export default { no: `nee`, yes: `ja` }, + copyToClipboard: { + copied: `{data} is naar het klembord gekopierd` + }, + errors: { + close: `sluit` + }, + fileSelect: { + defaultLabel: `Sleep hier een bestand naartoe, of klik om een bestand te selecteren voor uploaden` + }, + gasPriceSelector: { + customTooltip: { + transactions: `{number} {number, plural, one {transaction} other {transactions}} met een ingestelde gasprijs tussen de {minPrice} en {maxPrice}` + } + }, identityName: { null: `NUL`, unnamed: `NAAMLOOS` }, + methodDecoding: { + condition: { + block: `, {historic, select, true {Submitted} false {Submission}} in blok {blockNumber}`, + time: `, {historic, select, true {Submitted} false {Submission}} op {timestamp}` + }, + deploy: { + address: `Een contract aangemaakt op adres`, + params: `met de volgende parameters:`, + willDeploy: `Zal een contract aanmaken`, + withValue: `, verzenden van {value}` + }, + gasUsed: `({gas} gas gebruikt)`, + gasValues: `{gas} gas ({gasPrice}M/{tag})`, + input: { + data: `data`, + input: `input`, + withInput: `met de {inputDesc} {inputValue}` + }, + receive: { + contract: `het contract`, + info: `{historic, select, true {Received} false {Will receive}} {valueEth} van {aContract}{address}` + }, + signature: { + info: `{historic, select, true {Executed} false {Will execute}} the {method} function on the contract {address} transferring {ethValue}{inputLength, plural, zero {,} other {passing the following {inputLength, plural, one {parameter} other {parameters}}}}` + }, + token: { + transfer: `{historic, select, true {Transferred} false {Will transfer}} {value} naar {address}` + }, + transfer: { + contract: `het contract`, + info: `{historic, select, true {Transferred} false {Will transfer}} {valueEth} naar {aContract}{address}` + }, + txValues: `{historic, select, true {Provided} false {Provides}} {gasProvided}{gasUsed} voor een totale transactie waarde van {totalEthValue}`, + unknown: { + info: `{historic, select, true {Executed} false {Will execute}} the {method} on the contract {address} transferring {ethValue}.` + } + }, passwordStrength: { label: `wachtwoord sterkte` }, @@ -48,6 +131,10 @@ export default { posted: `De transactie is op het netwerk geplaatst met hash {hashLink}`, waiting: `wachten op bevestigingen` }, + vaultSelect: { + hint: `de kluis waaraan dit account gekoppeld is`, + label: `gekoppelde kluis` + }, verification: { gatherData: { accountHasRequested: { @@ -60,10 +147,6 @@ export default { pending: `Aan het controleren of je account is geverifieerd…`, true: `Je account is al geverifieerd.` }, - email: { - hint: `de code zal naar dit adres worden verzonden`, - label: `e-mail adres` - }, fee: `De extra vergoeding is {amount} ETH.`, isAbleToRequest: { pending: `Valideren van je invoer…` @@ -74,10 +157,6 @@ export default { true: `De verificatie server is actief.` }, nofee: `Er zijn geen extra kosten.`, - phoneNumber: { - hint: `De SMS zal naar dit nummer worden verstuurd`, - label: `telefoonnummer in internationaal formaat` - }, termsOfService: `Ik ga akkoord met de voorwaarden en condities hieronder.` } } diff --git a/js/src/i18n/nl/upgradeParity.js b/js/src/i18n/nl/upgradeParity.js index c057c9e7d..732a7b267 100644 --- a/js/src/i18n/nl/upgradeParity.js +++ b/js/src/i18n/nl/upgradeParity.js @@ -15,13 +15,13 @@ // along with Parity. If not, see . export default { - busy: `Parity wordt momenteel bijgewerkt naar versie {newversion}`, + busy: `Parity wordt momenteel bijgewerkt naar versie {newversion}. Wacht tot het proces is voltooid.`, button: { close: `sluiten`, done: `klaar`, upgrade: `werk nu bij` }, - completed: `Het bijwerken naar Parity {newversion} is succesvol voltooid.`, + completed: `Het bijwerken naar Parity {newversion} is succesvol voltooid. Klik op "klaar" om het programma automatisch opnieuw op te starten.`, consensus: { capable: `Je huidige versie van Parity voldoet aan de netwerk vereisten.`, capableUntil: `Je huidige versie van Parity voldoet aan de netwerk vereisten tot aan blok {blockNumber}`, @@ -30,7 +30,10 @@ export default { }, failed: `Het bijwerken naar Parity {newversion} gaf een fout en is mislukt.`, info: { - upgrade: `Een nieuwe versie van Parity, version {newversion} is beschikbaar als upgrade vanaf je huidige versie {currentversion}` + currentVersion: `Je huidige versie is {currentversion}`, + next: `Klik op "werk nu bij" om het bijwerken van je Parity te starten.`, + upgrade: `Een nieuwe versie {newversion} is beschikbaar`, + welcome: `Welkom bij de Parity upgrade wizard, deze stelt je in staat om Parity op zeer eenvoudige wijze bij te werken naar de nieuwste versie.` }, step: { completed: `bijwerken voltooid`, diff --git a/js/src/i18n/nl/vaults.js b/js/src/i18n/nl/vaults.js index b16c6807e..3659fb7d7 100644 --- a/js/src/i18n/nl/vaults.js +++ b/js/src/i18n/nl/vaults.js @@ -26,8 +26,9 @@ export default { button: { accounts: `accounts`, add: `Maak kluis`, - close: `sluit kluis`, - open: `open kluis` + close: `sluit`, + edit: `bewerk`, + open: `open` }, confirmClose: { info: `Je staat op het punt op een kluis te sluiten. Alle aan deze kluis verbonden accounts zullen niet meer zichtbaar zijn na het voltooien van deze actie. Om deze accounts weer zichtbaar te maken dien je de kluis weer te openen.`, @@ -70,6 +71,38 @@ export default { }, title: `Maak een nieuwe kluis aan` }, + editMeta: { + allowPassword: `Wijzig kluis wachtwoord`, + button: { + close: `sluit`, + save: `opslaan` + }, + currentPassword: { + hint: `je huidige kluis wachtwoord`, + label: `huidige wachtwoord` + }, + description: { + hint: `de omschrijving van deze kluis`, + label: `kluis omschrijving` + }, + password: { + hint: `een sterk, uniek wachtwoord`, + label: `nieuw wachtwoord` + }, + password2: { + hint: `verifieer je nieuwe wachtwoord`, + label: `nieuw wachtwoord (herhaal)` + }, + passwordHint: { + hint: `je wachtwoord hint voor deze kluis`, + label: `wachtwoord hint` + }, + title: `Bewerk Kluis Metadata` + }, empty: `Er zijn momenteel geen kluizen om weer tegeven.`, + selector: { + noneAvailable: `Er zijn momenteel geen kluizen geopend en beschikbaar voor selectie. Maak eerst een kluis aan en open deze, voordat je een kluis selecteert voor het verplaatsen van een account.`, + title: `Selecteer Account Kluis` + }, title: `Kluis Beheer` }; diff --git a/js/src/i18n/nl/verification.js b/js/src/i18n/nl/verification.js new file mode 100644 index 000000000..bd0ba1c28 --- /dev/null +++ b/js/src/i18n/nl/verification.js @@ -0,0 +1,85 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + button: { + cancel: `Annuleer`, + done: `Klaar`, + next: `Volgende` + }, + code: { + error: `ongeldige code`, + hint: `Voer de ontvangen code in.`, + label: `verificatie code`, + sent: `De verificatie code is verstuurd naar {receiver}.` + }, + confirmation: { + authorise: `De verificatie code zal naar het contract worden verzonden. Gebruik de Parity Signer om dit goed te keuren.`, + windowOpen: `Houd dit scherm open.` + }, + done: { + message: `Gefeliciteerd, je account is geverifieerd!` + }, + email: { + enterCode: `Voer de code in die je per e-email hebt ontvangen.` + }, + gatherData: { + email: { + hint: `de code zal naar dit adres worden verstuurd`, + label: `e-mail adres` + }, + phoneNumber: { + hint: `De SMS zal naar dit nummer worden verstuurd`, + label: `telefoon nummer in internationaal formaat` + } + }, + gatherDate: { + email: { + error: `ongeldig e-mail adres` + }, + phoneNumber: { + error: `ongeldig telefoon nummer` + } + }, + loading: `Laden van verificatie data.`, + request: { + authorise: `Een verificatie verzoek zal naar het contract worden verzonden. Gebruik de Parity Signer om dit goed te keuren.`, + requesting: `Een code aanvragen bij de Parity-server en wachten tot de puzzel in het contract opgenomen wordt.`, + windowOpen: `Houd dit scherm open.` + }, + sms: { + enterCode: `Voer de code in die je per SMS hebt ontvangen.` + }, + steps: { + code: `Voer Code in`, + completed: `Voltooi`, + confirm: `Bevestig`, + data: `Voer Data in`, + method: `Methode`, + request: `Verzoek` + }, + title: `verifieer je account`, + types: { + email: { + description: `De hash van het e-mail adres waarvan je bewijst dat het van jou is, zal worden opgeslagen in de blockchain.`, + label: `E-mail Verificatie` + }, + sms: { + description: `Het zal in de blockchain worden vast gelegd dat jij in het bezit bent van een telefoon nummer (not which).`, + label: `SMS Verificatie` + } + } +}; diff --git a/js/src/i18n/nl/wallet.js b/js/src/i18n/nl/wallet.js new file mode 100644 index 000000000..d0460e58f --- /dev/null +++ b/js/src/i18n/nl/wallet.js @@ -0,0 +1,45 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + buttons: { + edit: `bewerk`, + forget: `vergeet`, + settings: `instellingen`, + transfer: `verzend` + }, + confirmations: { + buttons: { + confirmAs: `Bevestig als...`, + revokeAs: `Herroep als...` + }, + none: `Er zijn momenteel geen transacties die op bevestiging wachten.`, + tooltip: { + confirmed: `Bevestigd door {number}/{required} eigenaren` + } + }, + details: { + requiredOwners: `Dit wallet vereist ten minste {owners} voor de goedkeuring van elke actie (transactions, modifications).`, + requiredOwnersNumber: `{number} {numberValue, plural, one {owner} other {owners}}`, + spent: `{spent} is vandaag besteed, van de {limit} ingestelde daglimiet. De daglimiet is op {date} opnieuw ingesteld`, + title: `Details` + }, + title: `Wallet Beheer`, + transactions: { + none: `Er zijn geen verzonden transacties.`, + title: `Transacties` + } +}; diff --git a/js/src/i18n/nl/walletSettings.js b/js/src/i18n/nl/walletSettings.js index ca0842944..66fd70001 100644 --- a/js/src/i18n/nl/walletSettings.js +++ b/js/src/i18n/nl/walletSettings.js @@ -15,6 +15,16 @@ // along with Parity. If not, see . export default { + addOwner: { + title: `Eigenaar toevoegen` + }, + buttons: { + cancel: `Annuleer`, + close: `Sluit`, + next: `Volgende`, + send: `Verzend`, + sending: `Verzenden...` + }, changes: { modificationString: `Om je wijzigingen door te voeren zullen andere eigenaren deze zelfde wijzigingen moeten verzenden. Om het @@ -25,7 +35,8 @@ export default { edit: { message: `Om de instellingen van dit contract de wijzigen zullen minimaal {owners, number} {owners, plural, one {owner } other {owners }} precies dezelfde - wijzigingen moeten verzenden. Je kunt hier de wijzigingen in string-vorm plakken.` + wijzigingen moeten verzenden. Je kunt de wijzigingen hier + in string-vorm plakken.` }, modifications: { daylimit: { @@ -47,11 +58,12 @@ export default { label: `van account (wallet eigenaar)` } }, - rejected: { - busyStep: { - state: `De wallet instellingen zullen niet worden gewijzigd. Je kunt dit venster veilig sluiten.`, - title: `De wijzigingen zijn afgewezen.` - }, - title: `afgewezen` + ownersChange: { + details: `van {from} naar {to}`, + title: `Wijzig Vereiste Eigenaren` + }, + rejected: `De transactie #{txid} is afgewezen`, + removeOwner: { + title: `Verwijder Eigenaar` } }; diff --git a/js/src/i18n/nl/writeContract.js b/js/src/i18n/nl/writeContract.js new file mode 100644 index 000000000..e264ac83a --- /dev/null +++ b/js/src/i18n/nl/writeContract.js @@ -0,0 +1,62 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default { + buttons: { + autoCompile: `Auto-Compile`, + compile: `Compileer`, + deploy: `Maak Aan`, + import: `Importeer Solidity`, + load: `Laad`, + new: `Nieuw`, + optimise: `Optimaliseer`, + save: `Opslaan` + }, + compiling: { + action: `Compileer de bron code.`, + busy: `Compileren...` + }, + details: { + saved: `(opgeslagen {timestamp})` + }, + error: { + noContract: `Er is geen contract gevonden.`, + params: `Een fout is opgetreden met de volgende omschrijving` + }, + input: { + abi: `ABI Interface`, + code: `Bytecode`, + metadata: `Metadata`, + swarm: `Swarm Metadata Hash` + }, + title: { + contract: `Selecteer een contract`, + loading: `Laden...`, + main: `Schrijf een Contract`, + messages: `Compiler berichten`, + new: `Nieuw Solidity Contract`, + parameters: `Parameters`, + saved: `opgeslagen @ {timestamp}`, + selectSolidity: `Selecteer een Solidity versie`, + solidity: `Solidity {version} laden` + }, + type: { + humanErc20: `Implementatie van het Human Token Contract`, + implementErc20: `Implementatie van ERC20 Token Contract`, + multisig: `Implementatie van een multisig Wallet`, + standardErc20: `Standaard ERC20 Token Contract` + } +}; From 770c7e5878cdb2b4e1783da116875022e71641a5 Mon Sep 17 00:00:00 2001 From: GitLab Build Bot Date: Wed, 19 Apr 2017 14:32:38 +0000 Subject: [PATCH 25/29] [ci skip] js-precompiled 20170419-142847 --- Cargo.lock | 2 +- js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dccc2f8df..f3109228a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1773,7 +1773,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#7b0c9ffdfa680f7792751f03d3490fc2a9fea23f" +source = "git+https://github.com/paritytech/js-precompiled.git#b4927eeaa876ff4daffda80ec85382fbd95f313c" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/js/package.json b/js/package.json index da567a458..ac1731b91 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.54", + "version": "1.7.55", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", From fc18299869f087ed212256faaef638f0d96a8636 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 19 Apr 2017 17:47:30 +0200 Subject: [PATCH 26/29] Background-repeat round (#5475) --- js/src/index.ejs | 1 + js/src/ui/ParityBackground/parityBackground.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/index.ejs b/js/src/index.ejs index ec8592b88..305568f5b 100644 --- a/js/src/index.ejs +++ b/js/src/index.ejs @@ -8,6 +8,7 @@