From 432c0d59c465e3ef96031a6f98fa354bd66c614d Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 5 Feb 2016 13:21:34 +0100 Subject: [PATCH 01/36] few additional rpc eth methods --- ethcore/src/views.rs | 10 ++++++++ rpc/src/v1/impls/eth.rs | 55 ++++++++++++++++++++++++++++++---------- rpc/src/v1/traits/eth.rs | 4 +++ rpc/src/v1/types/mod.rs | 2 ++ rpc/src/v1/types/sync.rs | 11 ++++++++ 5 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 rpc/src/v1/types/sync.rs diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index e1c704625..5117309c3 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -139,6 +139,11 @@ impl<'a> BlockView<'a> { self.rlp.val_at(1) } + /// Return number of transactions in given block, without deserializing them. + pub fn transactions_count(&self) -> usize { + self.rlp.at(1).iter().count() + } + /// Return List of transactions in given block. pub fn transaction_views(&self) -> Vec { self.rlp.at(1).iter().map(TransactionView::new_from_rlp).collect() @@ -154,6 +159,11 @@ impl<'a> BlockView<'a> { self.rlp.val_at(2) } + /// Return number of uncles in given block, without deserializing them. + pub fn uncles_count(&self) -> usize { + self.rlp.at(2).iter().count() + } + /// Return List of transactions in given block. pub fn uncle_views(&self) -> Vec { self.rlp.at(2).iter().map(HeaderView::new_from_rlp).collect() diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 46718601b..c1cd327df 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -7,7 +7,7 @@ use util::sha3::*; use ethcore::client::*; use ethcore::views::*; use v1::traits::{Eth, EthFilter}; -use v1::types::Block; +use v1::types::{Block, SyncStatus}; /// Eth rpc implementation. pub struct EthClient { @@ -24,6 +24,7 @@ impl EthClient { } impl Eth for EthClient { + // TODO: do not hardcode protocol version fn protocol_version(&self, params: Params) -> Result { match params { Params::None => Ok(Value::U64(63)), @@ -31,6 +32,15 @@ impl Eth for EthClient { } } + // TODO: do no hardcode default sync status + fn syncing(&self, params: Params) -> Result { + match params { + Params::None => to_value(&SyncStatus::default()), + _ => Err(Error::invalid_params()) + } + } + + // TODO: do not hardcode author. fn author(&self, params: Params) -> Result { match params { Params::None => to_value(&Address::new()), @@ -38,6 +48,23 @@ impl Eth for EthClient { } } + // TODO: return real value of mining once it's implemented. + fn is_mining(&self, params: Params) -> Result { + match params { + Params::None => Ok(Value::Bool(false)), + _ => Err(Error::invalid_params()) + } + } + + // TODO: return real hashrate once we have mining + fn hashrate(&self, params: Params) -> Result { + match params { + Params::None => Ok(Value::U64(0)), + _ => Err(Error::invalid_params()) + } + } + + // TODO: do not hardode gas_price fn gas_price(&self, params: Params) -> Result { match params { Params::None => Ok(Value::U64(0)), @@ -52,24 +79,26 @@ impl Eth for EthClient { } } - fn is_mining(&self, params: Params) -> Result { - match params { - Params::None => Ok(Value::Bool(false)), - _ => Err(Error::invalid_params()) + fn block_transaction_count(&self, params: Params) -> Result { + match from_params::(params) { + Ok(hash) => match self.client.block(&hash) { + Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), + None => Ok(Value::Null) + }, + Err(err) => Err(err) } } - fn hashrate(&self, params: Params) -> Result { - match params { - Params::None => Ok(Value::U64(0)), - _ => Err(Error::invalid_params()) + fn block_uncles_count(&self, params: Params) -> Result { + match from_params::(params) { + Ok(hash) => match self.client.block(&hash) { + Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), + None => Ok(Value::Null) + }, + Err(err) => Err(err) } } - fn block_transaction_count(&self, _: Params) -> Result { - Ok(Value::U64(0)) - } - fn block(&self, params: Params) -> Result { match from_params::<(H256, bool)>(params) { Ok((hash, _include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) { diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 3dcdfdf05..e9134d84a 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -7,6 +7,9 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns protocol version. fn protocol_version(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns an object with data about the sync status or false. (wtf?) + fn syncing(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns the number of hashes per second that the node is mining with. fn hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -92,6 +95,7 @@ pub trait Eth: Sized + Send + Sync + 'static { fn to_delegate(self) -> IoDelegate { let mut delegate = IoDelegate::new(Arc::new(self)); delegate.add_method("eth_protocolVersion", Eth::protocol_version); + delegate.add_method("eth_syncing", Eth::syncing); delegate.add_method("eth_hashrate", Eth::hashrate); delegate.add_method("eth_coinbase", Eth::author); delegate.add_method("eth_mining", Eth::is_mining); diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 7be32e84d..b0ffff2ae 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -1,3 +1,5 @@ mod block; +mod sync; pub use self::block::Block; +pub use self::sync::SyncStatus; diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs new file mode 100644 index 000000000..b13b7167a --- /dev/null +++ b/rpc/src/v1/types/sync.rs @@ -0,0 +1,11 @@ +use util::hash::*; + +#[derive(Default, Debug, Serialize)] +pub struct SyncStatus { + #[serde(rename="startingBlock")] + pub starting_block: H256, + #[serde(rename="currentBlock")] + pub current_block: H256, + #[serde(rename="highestBlock")] + pub highest_block: H256, +} From 3adfebdc2039a50f7c5d1a1dca4efaefb8d1e1f3 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 8 Feb 2016 10:58:08 +0100 Subject: [PATCH 02/36] jsonrpc eth_getCode method --- ethcore/src/client.rs | 7 ++++ rpc/Cargo.toml | 2 +- rpc/src/lib.rs | 1 + rpc/src/v1/impls/eth.rs | 10 ++++- rpc/src/v1/types/block_number.rs | 68 ++++++++++++++++++++++++++++++++ rpc/src/v1/types/bytes.rs | 37 +++++++++++++++++ rpc/src/v1/types/mod.rs | 4 ++ 7 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 rpc/src/v1/types/block_number.rs create mode 100644 rpc/src/v1/types/bytes.rs diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 3a0309c1c..28181f5fa 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -86,6 +86,9 @@ pub trait BlockChainClient : Sync + Send { /// Get block total difficulty. fn block_total_difficulty(&self, hash: &H256) -> Option; + /// Get address code. + fn code(&self, address: &Address) -> Option; + /// Get raw block header data by block number. fn block_header_at(&self, n: BlockNumber) -> Option; @@ -357,6 +360,10 @@ impl BlockChainClient for Client { self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty) } + fn code(&self, address: &Address) -> Option { + self.state().code(address) + } + fn block_header_at(&self, n: BlockNumber) -> Option { self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h)) } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index bea85a74f..66688466c 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,4 +18,4 @@ ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } clippy = "0.0.37" target_info = "0.1.0" - +rustc-serialize = "0.3" diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index bf82a64a0..0b148c983 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,6 +20,7 @@ #![plugin(serde_macros)] #![plugin(clippy)] +extern crate rustc_serialize; extern crate target_info; extern crate serde; extern crate serde_json; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 72687e03c..d8bcf9540 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,7 +23,7 @@ use util::sha3::*; use ethcore::client::*; use ethcore::views::*; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, SyncStatus}; +use v1::types::{Block, BlockNumber, Bytes, SyncStatus}; /// Eth rpc implementation. pub struct EthClient { @@ -115,6 +115,14 @@ impl Eth for EthClient { } } + // TODO: do not ignore block number param + fn code_at(&self, params: Params) -> Result { + match from_params::<(Address, BlockNumber)>(params) { + Ok((address, _block_number)) => to_value(&Bytes::new(self.client.code(&address).unwrap_or_else(|| vec![]))), + Err(err) => Err(err) + } + } + fn block(&self, params: Params) -> Result { match from_params::<(H256, bool)>(params) { Ok((hash, _include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) { diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs new file mode 100644 index 000000000..bfe20f177 --- /dev/null +++ b/rpc/src/v1/types/block_number.rs @@ -0,0 +1,68 @@ +// Copyright 2015, 2016 Ethcore (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 serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; + +/// Represents rpc api block number param. +#[derive(Debug, PartialEq)] +pub enum BlockNumber { + Num(u64), + Latest, + Earliest, + Pending +} + +impl Deserialize for BlockNumber { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.visit(BlockNumberVisitor) + } +} + +struct BlockNumberVisitor; + +impl Visitor for BlockNumberVisitor { + type Value = BlockNumber; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + match value { + "latest" => Ok(BlockNumber::Latest), + "earliest" => Ok(BlockNumber::Earliest), + "pending" => Ok(BlockNumber::Pending), + _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")), + _ => value.parse::().map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")) + } + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn block_number_deserialization() { + let s = r#"["0xa", "10", "latest", "earliest", "pending"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![BlockNumber::Num(10), BlockNumber::Num(10), BlockNumber::Latest, BlockNumber::Earliest, BlockNumber::Pending]) + } +} + diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs new file mode 100644 index 000000000..51cb7f333 --- /dev/null +++ b/rpc/src/v1/types/bytes.rs @@ -0,0 +1,37 @@ +use rustc_serialize::hex::ToHex; +use serde::{Serialize, Serializer}; + +/// Wrapper structure around vector of bytes. +pub struct Bytes(Vec); + +impl Bytes { + /// Simple constructor. + pub fn new(bytes: Vec) -> Bytes { + Bytes(bytes) + } +} + +impl Serialize for Bytes { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: Serializer { + let mut serialized = "0x".to_owned(); + serialized.push_str(self.0.to_hex().as_ref()); + serializer.visit_str(serialized.as_ref()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + use rustc_serialize::hex::FromHex; + + #[test] + fn test_bytes_serialize() { + let bytes = Bytes("0123456789abcdef".from_hex().unwrap()); + let serialized = serde_json::to_string(&bytes).unwrap(); + assert_eq!(serialized, r#""0x0123456789abcdef""#); + } +} + + diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 1b03485ab..0b8582910 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -15,7 +15,11 @@ // along with Parity. If not, see . mod block; +mod block_number; +mod bytes; mod sync; pub use self::block::Block; +pub use self::block_number::BlockNumber; +pub use self::bytes::Bytes; pub use self::sync::SyncStatus; From b2c083ce560f436681b3851d993ef430730a2c85 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 8 Feb 2016 11:58:47 +0100 Subject: [PATCH 03/36] fixed U256 serialization, tests for transaction serialization --- rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/mod.rs | 2 ++ rpc/src/v1/tests/mod.rs | 1 + rpc/src/v1/types/bytes.rs | 8 ++++++++ rpc/src/v1/types/mod.rs | 2 ++ rpc/src/v1/types/transaction.rs | 36 +++++++++++++++++++++++++++++++++ util/src/uint.rs | 3 ++- 7 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 rpc/src/v1/tests/mod.rs create mode 100644 rpc/src/v1/types/transaction.rs diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d8bcf9540..f90995ffe 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -118,7 +118,7 @@ impl Eth for EthClient { // TODO: do not ignore block number param fn code_at(&self, params: Params) -> Result { match from_params::<(Address, BlockNumber)>(params) { - Ok((address, _block_number)) => to_value(&Bytes::new(self.client.code(&address).unwrap_or_else(|| vec![]))), + Ok((address, _block_number)) => to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new)), Err(err) => Err(err) } } diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 11a5291b5..01635e872 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -21,6 +21,8 @@ pub mod traits; mod impls; mod types; +#[cfg(test)] +mod tests; pub use self::traits::{Web3, Eth, EthFilter, Net}; pub use self::impls::*; diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs new file mode 100644 index 000000000..bdf4567b6 --- /dev/null +++ b/rpc/src/v1/tests/mod.rs @@ -0,0 +1 @@ +//TODO: load custom blockchain state and test diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 51cb7f333..62aca8464 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -2,6 +2,7 @@ use rustc_serialize::hex::ToHex; use serde::{Serialize, Serializer}; /// Wrapper structure around vector of bytes. +#[derive(Debug)] pub struct Bytes(Vec); impl Bytes { @@ -11,6 +12,13 @@ impl Bytes { } } +impl Default for Bytes { + fn default() -> Self { + // default serialized value is 0x00 + Bytes(vec![0]) + } +} + impl Serialize for Bytes { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 0b8582910..226e7e9a6 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -18,8 +18,10 @@ mod block; mod block_number; mod bytes; mod sync; +mod transaction; pub use self::block::Block; pub use self::block_number::BlockNumber; pub use self::bytes::Bytes; pub use self::sync::SyncStatus; +pub use self::transaction::Transaction; diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs new file mode 100644 index 000000000..de4490cbb --- /dev/null +++ b/rpc/src/v1/types/transaction.rs @@ -0,0 +1,36 @@ +use util::hash::*; +use util::uint::*; +use v1::types::Bytes; + +#[derive(Debug, Default, Serialize)] +pub struct Transaction { + hash: H256, + nonce: U256, + #[serde(rename="blockHash")] + block_hash: H256, + #[serde(rename="blockNumber")] + block_number: U256, + #[serde(rename="transactionIndex")] + transaction_index: U256, + from: Address, + to: Address, + value: U256, + #[serde(rename="gasPrice")] + gas_price: U256, + gas: U256, + input: Bytes +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn test_transaction_serialize() { + let t = Transaction::default(); + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#); + } +} + diff --git a/util/src/uint.rs b/util/src/uint.rs index 4c0b533ef..b3427f6bc 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -458,7 +458,8 @@ macro_rules! construct_uint { let mut hex = "0x".to_owned(); let mut bytes = [0u8; 8 * $n_words]; self.to_bytes(&mut bytes); - hex.push_str(bytes.to_hex().as_ref()); + let len = cmp::max((self.bits() + 7) / 8, 1); + hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref()); serializer.visit_str(hex.as_ref()) } } From a0451a3cb5a360af459ecc8afa498b6181695e31 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 8 Feb 2016 12:13:05 +0100 Subject: [PATCH 04/36] eth_getBlockXXX takes into account include_tx param --- rpc/src/v1/impls/eth.rs | 13 ++++++++++--- rpc/src/v1/types/block.rs | 27 ++++++++++++++++++++++----- rpc/src/v1/types/mod.rs | 2 +- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index f90995ffe..606a1ba6d 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,7 +23,7 @@ use util::sha3::*; use ethcore::client::*; use ethcore::views::*; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockNumber, Bytes, SyncStatus}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus}; /// Eth rpc implementation. pub struct EthClient { @@ -125,7 +125,7 @@ impl Eth for EthClient { fn block(&self, params: Params) -> Result { match from_params::<(H256, bool)>(params) { - Ok((hash, _include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) { + Ok((hash, include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) { (Some(bytes), Some(total_difficulty)) => { let view = HeaderView::new(&bytes); let block = Block { @@ -145,7 +145,14 @@ impl Eth for EthClient { difficulty: view.difficulty(), total_difficulty: total_difficulty, uncles: vec![], - transactions: vec![] + transactions: { + if include_txs { + BlockTransactions::Hashes(vec![]) + } else { + BlockTransactions::Full(vec![]) + } + }, + extra_data: Bytes::default() }; to_value(&block) }, diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 92ff5c8a6..ae5e59fbd 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -14,10 +14,28 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use serde::{Serialize, Serializer}; use util::hash::*; use util::uint::*; +use v1::types::{Bytes, Transaction}; -#[derive(Default, Debug, Serialize)] +#[derive(Debug)] +pub enum BlockTransactions { + Hashes(Vec), + Full(Vec) +} + +impl Serialize for BlockTransactions { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: Serializer { + match *self { + BlockTransactions::Hashes(ref hashes) => hashes.serialize(serializer), + BlockTransactions::Full(ref ts) => ts.serialize(serializer) + } + } +} + +#[derive(Debug, Serialize)] pub struct Block { pub hash: H256, #[serde(rename="parentHash")] @@ -38,9 +56,8 @@ pub struct Block { pub gas_used: U256, #[serde(rename="gasLimit")] pub gas_limit: U256, - // TODO: figure out how to properly serialize bytes - //#[serde(rename="extraData")] - //extra_data: Vec, + #[serde(rename="extraData")] + pub extra_data: Bytes, #[serde(rename="logsBloom")] pub logs_bloom: H2048, pub timestamp: U256, @@ -48,5 +65,5 @@ pub struct Block { #[serde(rename="totalDifficulty")] pub total_difficulty: U256, pub uncles: Vec, - pub transactions: Vec + pub transactions: BlockTransactions } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 226e7e9a6..2286c69a1 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -20,7 +20,7 @@ mod bytes; mod sync; mod transaction; -pub use self::block::Block; +pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; pub use self::bytes::Bytes; pub use self::sync::SyncStatus; From 41e64bff4e43c290011fdfb608dc06cac189d741 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 8 Feb 2016 14:02:47 +0100 Subject: [PATCH 05/36] tests for block serialization --- rpc/src/v1/types/block.rs | 49 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index ae5e59fbd..59cafcf60 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -21,7 +21,7 @@ use v1::types::{Bytes, Transaction}; #[derive(Debug)] pub enum BlockTransactions { - Hashes(Vec), + Hashes(Vec), Full(Vec) } @@ -67,3 +67,50 @@ pub struct Block { pub uncles: Vec, pub transactions: BlockTransactions } + +#[cfg(test)] +mod tests { + use serde_json; + use util::hash::*; + use util::uint::*; + use v1::types::{Transaction, Bytes}; + use super::*; + + #[test] + fn test_serialize_block_transactions() { + let t = BlockTransactions::Full(vec![Transaction::default()]); + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#); + + let t = BlockTransactions::Hashes(vec![H256::default()]); + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!(serialized, r#"["0x0000000000000000000000000000000000000000000000000000000000000000"]"#); + } + + #[test] + fn test_serialize_block() { + let block = Block { + hash: H256::default(), + parent_hash: H256::default(), + uncles_hash: H256::default(), + author: Address::default(), + miner: Address::default(), + state_root: H256::default(), + transactions_root: H256::default(), + receipts_root: H256::default(), + number: U256::default(), + gas_used: U256::default(), + gas_limit: U256::default(), + extra_data: Bytes::default(), + logs_bloom: H2048::default(), + timestamp: U256::default(), + difficulty: U256::default(), + total_difficulty: U256::default(), + uncles: vec![], + transactions: BlockTransactions::Hashes(vec![]) + }; + + let serialized = serde_json::to_string(&block).unwrap(); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x00","gasUsed":"0x00","gasLimit":"0x00","extraData":"0x00","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x00","difficulty":"0x00","totalDifficulty":"0x00","uncles":[],"transactions":[]}"#); + } +} From 483ee1fbceb3bc2d5edb8b5945a7d73b4282e017 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 8 Feb 2016 15:53:22 +0100 Subject: [PATCH 06/36] blockchain transaction api --- ethcore/src/blockchain.rs | 43 +++++++++++++++++++++++++++++++++++++ ethcore/src/extras.rs | 2 +- ethcore/src/transaction.rs | 12 ++++++++--- ethcore/src/verification.rs | 4 ++++ 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 4c765360e..ff1e508d3 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -85,6 +85,9 @@ pub trait BlockProvider { /// Get the hash of given block's number. fn block_hash(&self, index: BlockNumber) -> Option; + /// Get the address of transaction with given hash. + fn transaction_address(&self, hash: &H256) -> Option; + /// Get the partial-header of a block. fn block_header(&self, hash: &H256) -> Option
{ self.block(hash).map(|bytes| BlockView::new(&bytes).header()) @@ -107,6 +110,16 @@ pub trait BlockProvider { self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number()) } + /// Get transaction with given transaction hash. + fn transaction(&self, hash: &H256) -> Option { + self.transaction_address(hash).and_then(|address| self.transaction_at(&address)) + } + + /// Get transaction at given address. + fn transaction_at(&self, address: &TransactionAddress) -> Option { + self.block(&address.block_hash).map(|bytes| BlockView::new(&bytes).transactions()).and_then(|t| t.into_iter().nth(address.index)) + } + /// Get a list of transactions for a given block. /// Returns None if block deos not exist. fn transactions(&self, hash: &H256) -> Option> { @@ -201,6 +214,11 @@ impl BlockProvider for BlockChain { fn block_hash(&self, index: BlockNumber) -> Option { self.query_extras(&index, &self.block_hashes) } + + /// Get the address of transaction with given hash. + fn transaction_address(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.transaction_addresses) + } } const COLLECTION_QUEUE_SIZE: usize = 8; @@ -474,6 +492,14 @@ impl BlockChain { parent_details.children.push(hash.clone()); batch.put_extras(&parent_hash, &parent_details); + // update transaction addresses + for (i, tx_hash) in block.transaction_hashes().iter().enumerate() { + batch.put_extras(tx_hash, &TransactionAddress { + block_hash: hash.clone(), + index: i + }); + } + // if it's not new best block, just return if !is_new_best { return (batch, None, details); @@ -824,4 +850,21 @@ mod tests { let bc = bc_result.reference(); assert_eq!(bc.best_block_number(), 0); } + + #[test] + fn find_transaction_by_hash() { + let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap(); + let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap(); + let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(&genesis, temp.as_path()); + bc.insert_block(&b1); + + let transactions = bc.transactions(&b1_hash).unwrap(); + assert_eq!(transactions.len(), 7); + for t in transactions { + assert_eq!(bc.transaction(&t.hash()).unwrap(), t); + } + } } diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index f29925483..b65d4ed7a 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -260,7 +260,7 @@ pub struct TransactionAddress { /// Block hash pub block_hash: H256, /// Transaction index within the block - pub index: u64 + pub index: usize } impl ExtrasIndexable for TransactionAddress { diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index d90a0dd15..119f565dd 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -20,7 +20,7 @@ use util::*; use error::*; use evm::Schedule; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] /// Transaction action type. pub enum Action { /// Create creates new contract. @@ -45,7 +45,7 @@ impl Decodable for Action { /// A set of information describing an externally-originating message call /// or contract creation operation. -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Transaction { /// Nonce. pub nonce: U256, @@ -158,7 +158,7 @@ impl Transaction { -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq)] pub struct SignedTransaction { /// Plain Transaction. unsigned: Transaction, @@ -174,6 +174,12 @@ pub struct SignedTransaction { sender: RefCell> } +impl PartialEq for SignedTransaction { + fn eq(&self, other: &SignedTransaction) -> bool { + self.unsigned == other.unsigned && self.v == other.v && self.r == other.r && self.s == other.s + } +} + impl Deref for SignedTransaction { type Target = Transaction; diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index f827f365e..c7d5e265f 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -294,6 +294,10 @@ mod tests { }) } + fn transaction_address(&self, _hash: &H256) -> Option { + unimplemented!() + } + /// Get the hash of given block's number. fn block_hash(&self, index: BlockNumber) -> Option { self.numbers.get(&index).cloned() From e5e33826a7fd097fbf08e1de4746fa3bcaed820d Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 8 Feb 2016 16:07:38 +0100 Subject: [PATCH 07/36] fixed failin ethsync test --- sync/src/tests/helpers.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index a5a60d62d..ee052ed5a 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -76,6 +76,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn code(&self, _address: &Address) -> Option { + unimplemented!(); + } + fn block_header(&self, h: &H256) -> Option { self.blocks.read().unwrap().get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec()) From 7bc340956fb1da67c9e9554950dfa0cbbcf4dfe7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 8 Feb 2016 16:57:57 +0100 Subject: [PATCH 08/36] Correct node id for bootnode. --- ethcore/res/ethereum/frontier.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index 4f0a836ff..301441958 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -30,7 +30,7 @@ "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", "enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303", "enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", - "enode://859bbe6926fc161d218f62bd2efe0b4f6980205c00a5b928ccee39c94c440b73a054ece5db36beddd71963fbd296af61ec72a591f72a2299f9a046bd6d6ce1a9@parity-node-zero.ethcore.io:30303" + "enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@parity-node-zero.ethcore.io:30303" ], "accounts": { "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, From 1ae7db2e035be7b8611dd4414b570ef4512f58b9 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 8 Feb 2016 23:07:14 +0300 Subject: [PATCH 09/36] coverage & panics avoidance --- ethcore/src/ethereum/ethash.rs | 154 +++++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 34 deletions(-) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 43e3720d2..c4ebb7e62 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -23,8 +23,6 @@ use spec::*; use engine::*; use evm::Schedule; use evm::Factory; -#[cfg(test)] -use tests::helpers::*; /// Engine using Ethash proof-of-work consensus algorithm, suitable for Ethereum /// mainnet chains in the Olympic, Frontier and Homestead eras. @@ -49,6 +47,17 @@ impl Ethash { }) } + #[cfg(test)] + fn new_test(spec: Spec) -> Ethash { + Ethash { + spec: spec, + pow: EthashManager::new(), + factory: Factory::default(), + u64_params: RwLock::new(HashMap::new()), + u256_params: RwLock::new(HashMap::new()) + } + } + fn u64_param(&self, name: &str) -> u64 { *self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a))) @@ -123,6 +132,11 @@ impl Engine for Ethash { fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { // check the seal fields. + if header.seal.len() != self.seal_fields() { + return Err(From::from(BlockError::InvalidSealArity( + Mismatch { expected: self.seal_fields(), found: header.seal.len() } + ))); + } try!(UntrustedRlp::new(&header.seal[0]).as_val::()); try!(UntrustedRlp::new(&header.seal[1]).as_val::()); @@ -242,38 +256,110 @@ impl Header { } } -#[test] -fn on_close_block() { +#[cfg(test)] +mod tests { + extern crate ethash; + + use common::*; + use block::*; + use spec::*; + use engine::*; + use evm::Schedule; + use evm::Factory; + use tests::helpers::*; use super::*; - let engine = new_morden().to_engine().unwrap(); - let genesis_header = engine.spec().genesis_header(); - let mut db_result = get_temp_journal_db(); - let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); - let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); - let b = b.close(); - assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); + use super::super::new_morden; + + #[test] + fn on_close_block() { + let engine = new_morden().to_engine().unwrap(); + let genesis_header = engine.spec().genesis_header(); + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(&mut db); + let last_hashes = vec![genesis_header.hash()]; + let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let b = b.close(); + assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); + } + + #[test] + fn on_close_block_with_uncle() { + let engine = new_morden().to_engine().unwrap(); + let genesis_header = engine.spec().genesis_header(); + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(&mut db); + let last_hashes = vec![genesis_header.hash()]; + let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let mut uncle = Header::new(); + let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); + uncle.author = uncle_author.clone(); + b.push_uncle(uncle).unwrap(); + + let b = b.close(); + assert_eq!(b.state().balance(&Address::zero()), U256::from_str("478eae0e571ba000").unwrap()); + assert_eq!(b.state().balance(&uncle_author), U256::from_str("3cb71f51fc558000").unwrap()); + } + + #[test] + fn has_valid_metadata() { + let engine = Ethash::new_boxed(new_morden()); + assert!(!engine.name().is_empty()); + assert!(engine.version().major >= 1); + } + + #[test] + fn can_return_params() { + let engine = Ethash::new_test(new_morden()); + assert!(engine.u64_param("durationLimit") > 0); + assert!(engine.u256_param("minimumDifficulty") > U256::zero()); + } + + #[test] + fn can_return_factory() { + let engine = Ethash::new_test(new_morden()); + let factory = engine.vm_factory(); + } + + #[test] + fn can_return_schedule() { + let engine = Ethash::new_test(new_morden()); + let schedule = engine.schedule(&EnvInfo { + number: 10000000, + author: x!(0), + timestamp: 0, + difficulty: x!(0), + last_hashes: vec![], + gas_used: x!(0), + gas_limit: x!(0) + }); + + assert!(schedule.stack_limit > 0); + + let schedule = engine.schedule(&EnvInfo { + number: 100, + author: x!(0), + timestamp: 0, + difficulty: x!(0), + last_hashes: vec![], + gas_used: x!(0), + gas_limit: x!(0) + }); + + assert!(!schedule.have_delegate_call); + } + + #[test] + fn can_do_basic_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let header: Header = Header::default(); + + let verify_result = engine.verify_block_basic(&header, None); + + assert!(!verify_result.is_ok()); + } + + // TODO: difficulty test } -#[test] -fn on_close_block_with_uncle() { - use super::*; - let engine = new_morden().to_engine().unwrap(); - let genesis_header = engine.spec().genesis_header(); - let mut db_result = get_temp_journal_db(); - let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); - let last_hashes = vec![genesis_header.hash()]; - let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); - let mut uncle = Header::new(); - let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); - uncle.author = uncle_author.clone(); - b.push_uncle(uncle).unwrap(); - - let b = b.close(); - assert_eq!(b.state().balance(&Address::zero()), U256::from_str("478eae0e571ba000").unwrap()); - assert_eq!(b.state().balance(&uncle_author), U256::from_str("3cb71f51fc558000").unwrap()); -} - -// TODO: difficulty test From 22dd075692ba8304575c2f7ea109a989eae830dd Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 8 Feb 2016 23:43:53 +0300 Subject: [PATCH 10/36] proper fail conditions --- ethcore/src/ethereum/ethash.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index c4ebb7e62..f49725ab3 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -351,13 +351,30 @@ mod tests { } #[test] - fn can_do_basic_verification_fail() { + fn can_do_seal_verification_fail() { let engine = Ethash::new_test(new_morden()); let header: Header = Header::default(); let verify_result = engine.verify_block_basic(&header, None); - assert!(!verify_result.is_ok()); + match verify_result { + Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + _ => { panic!("should be block difficulty error"); } + } + } + + #[test] + fn can_do_difficulty_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + + let verify_result = engine.verify_block_basic(&header, None); + + match verify_result { + Err(Error::Block(BlockError::DifficultyOutOfBounds(_))) => {}, + _ => { panic!("should be block difficulty error"); } + } } // TODO: difficulty test From fc0153a5a46c0f14c8948d57bd4c655e5131af1e Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 00:54:33 +0300 Subject: [PATCH 11/36] returning client to the place it should be, cleanup --- ethcore/src/ethereum/ethash.rs | 23 ++++++++++++++++----- ethcore/src/evm/factory.rs | 2 ++ ethcore/src/executive.rs | 5 ++++- ethcore/src/json_tests/mod.rs | 1 - ethcore/src/{json_tests => tests}/client.rs | 2 +- ethcore/src/tests/helpers.rs | 4 ---- ethcore/src/tests/mod.rs | 1 + 7 files changed, 26 insertions(+), 12 deletions(-) rename ethcore/src/{json_tests => tests}/client.rs (99%) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index f49725ab3..7d99a456a 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -262,10 +262,7 @@ mod tests { use common::*; use block::*; - use spec::*; use engine::*; - use evm::Schedule; - use evm::Factory; use tests::helpers::*; use super::*; use super::super::new_morden; @@ -319,7 +316,7 @@ mod tests { #[test] fn can_return_factory() { let engine = Ethash::new_test(new_morden()); - let factory = engine.vm_factory(); + engine.vm_factory(); } #[test] @@ -359,7 +356,7 @@ mod tests { match verify_result { Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, - _ => { panic!("should be block difficulty error"); } + _ => { panic!("should be block seal mismatch error"); } } } @@ -377,6 +374,22 @@ mod tests { } } + #[test] + fn can_do_proof_of_work_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); + + let verify_result = engine.verify_block_basic(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + _ => { panic!("should be invalid proof of work error"); } + } + + } + // TODO: difficulty test } diff --git a/ethcore/src/evm/factory.rs b/ethcore/src/evm/factory.rs index f1be0e427..4a9bd38ba 100644 --- a/ethcore/src/evm/factory.rs +++ b/ethcore/src/evm/factory.rs @@ -159,11 +159,13 @@ macro_rules! evm_test_ignore( #[test] #[ignore] #[cfg(feature = "jit")] + #[cfg(feature = "ignored-tests")] fn $name_jit() { $name_test(Factory::new(VMType::Jit)); } #[test] #[ignore] + #[cfg(feature = "ignored-tests")] fn $name_int() { $name_test(Factory::new(VMType::Interpreter)); } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 2d6039953..812dc3acd 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -360,6 +360,7 @@ impl<'a> Executive<'a> { } #[cfg(test)] +#[allow(dead_code)] mod tests { use super::*; use common::*; @@ -599,6 +600,7 @@ mod tests { } // test is incorrect, mk + // TODO: fix (preferred) or remove evm_test_ignore!{test_aba_calls: test_aba_calls_jit, test_aba_calls_int} fn test_aba_calls(factory: Factory) { // 60 00 - push 0 @@ -659,6 +661,7 @@ mod tests { } // test is incorrect, mk + // TODO: fix (preferred) or remove evm_test_ignore!{test_recursive_bomb1: test_recursive_bomb1_jit, test_recursive_bomb1_int} fn test_recursive_bomb1(factory: Factory) { // 60 01 - push 1 @@ -704,6 +707,7 @@ mod tests { } // test is incorrect, mk + // TODO: fix (preferred) or remove evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int} fn test_transact_simple(factory: Factory) { let keypair = KeyPair::create().unwrap(); @@ -902,5 +906,4 @@ mod tests { } } } - } diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs index 1cae0fa1d..df67de76d 100644 --- a/ethcore/src/json_tests/mod.rs +++ b/ethcore/src/json_tests/mod.rs @@ -20,7 +20,6 @@ mod test_common; mod transaction; mod executive; mod state; -mod client; mod chain; mod homestead_state; mod homestead_chain; diff --git a/ethcore/src/json_tests/client.rs b/ethcore/src/tests/client.rs similarity index 99% rename from ethcore/src/json_tests/client.rs rename to ethcore/src/tests/client.rs index 2d3166c74..697647187 100644 --- a/ethcore/src/json_tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . use client::{BlockChainClient,Client}; -use super::test_common::*; use tests::helpers::*; +use common::*; #[test] fn created() { diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 9ec36fa93..f5815b718 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -#[cfg(feature = "json-tests")] use client::{BlockChainClient, Client}; use std::env; use common::*; @@ -134,7 +133,6 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans rlp.out() } -#[cfg(feature = "json-tests")] pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { let dir = RandomTempPath::new(); @@ -174,7 +172,6 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult } } -#[cfg(feature = "json-tests")] pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { let dir = RandomTempPath::new(); let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); @@ -271,7 +268,6 @@ pub fn get_good_dummy_block() -> Bytes { create_test_block(&block_header) } -#[cfg(feature = "json-tests")] pub fn get_bad_state_dummy_block() -> Bytes { let mut block_header = Header::new(); let test_spec = get_test_spec(); diff --git a/ethcore/src/tests/mod.rs b/ethcore/src/tests/mod.rs index a4e13730a..28c1b3b5b 100644 --- a/ethcore/src/tests/mod.rs +++ b/ethcore/src/tests/mod.rs @@ -15,3 +15,4 @@ // along with Parity. If not, see . pub mod helpers; +mod client; \ No newline at end of file From e911e6470424576878a0b9156a4cdd2294c8abda Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 10:19:04 +0100 Subject: [PATCH 12/36] db_version 2 --- util/src/journaldb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index d9d7b29cf..28dcacbfa 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -50,7 +50,7 @@ impl Clone for JournalDB { const LAST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; const VERSION_KEY : [u8; 4] = [ b'j', b'v', b'e', b'r' ]; -const DB_VERSION: u32 = 1; +const DB_VERSION: u32 = 2; impl JournalDB { /// Create a new instance given a `backing` database. From 83fe91c88f4b34a35aa16415fc328fe96cc18f4b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 9 Feb 2016 11:39:04 +0100 Subject: [PATCH 13/36] Install script avoids compiling on Ubuntu. --- install-parity.sh | 198 ++++++---------------------------------------- 1 file changed, 23 insertions(+), 175 deletions(-) diff --git a/install-parity.sh b/install-parity.sh index 51eb806eb..ea0cfc4b6 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -201,16 +201,16 @@ function run_installer() source /etc/lsb-release if [[ $DISTRIB_ID == "Ubuntu" ]]; then - if [[ $DISTRIB_RELEASE == "14.04" ]]; then - check "Ubuntu-14.04" - isUbuntu1404=true + if [[ $DISTRIB_RELEASE == "14.04" || $DISTRIB_RELEASE == "15.04" || $DISTRIB_RELEASE == "15.10" ]]; then + check "Ubuntu" + isUbuntu=true else - check "Ubuntu, but not 14.04" - isUbuntu1404=false + check "Ubuntu, but version not supported" + isUbuntu=false fi else check "Ubuntu not found" - isUbuntu1404=false + isUbuntu=false fi } @@ -286,32 +286,6 @@ function run_installer() fi } - function find_multirust() - { - depCount=$((depCount+2)) - MULTIRUST_PATH=`which multirust 2>/dev/null` - if [[ -f $MULTIRUST_PATH ]]; then - depFound=$((depFound+1)) - check "multirust" - isMultirust=true - if [[ $(multirust show-default 2>/dev/null | grep nightly | wc -l) == 4 ]]; then - depFound=$((depFound+1)) - check "rust nightly" - isMultirustNightly=true - else - uncheck "rust is not nightly" - isMultirustNightly=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tmultirust -> rust nightly\n" - fi - else - uncheck "multirust is missing" - uncheck "rust nightly is missing" - isMultirust=false - isMultirustNightly=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tmultirust\n" - fi - } - function find_apt() { depCount=$((depCount+1)) @@ -327,112 +301,12 @@ function run_installer() uncheck "apt-get is missing" isApt=false - if [[ $isGCC == false || $isGit == false || $isMake == false || $isCurl == false ]]; then - canContinue=false - errorMessages+="${red}==>${reset} ${b}Couldn't find apt-get:${reset} We can only use apt-get in order to grab our dependencies.\n" - errorMessages+=" Please switch to a distribution such as Debian or Ubuntu or manually install the missing packages.\n" - fi + canContinue=false + errorMessages+="${red}==>${reset} ${b}Couldn't find apt-get:${reset} We can only use apt-get in order to grab our dependencies.\n" + errorMessages+=" Please switch to a distribution such as Debian or Ubuntu or manually install the missing packages.\n" fi } - function find_gcc() - { - depCount=$((depCount+1)) - GCC_PATH=`which g++ 2>/dev/null` - - if [[ -f $GCC_PATH ]] - then - depFound=$((depFound+1)) - check "g++" - isGCC=true - else - uncheck "g++ is missing" - isGCC=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tg++\n" - fi - } - - function find_git() - { - depCount=$((depCount+1)) - GIT_PATH=`which git 2>/dev/null` - - if [[ -f $GIT_PATH ]] - then - depFound=$((depFound+1)) - check "git" - isGit=true - else - uncheck "git is missing" - isGit=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tgit\n" - fi - } - - function find_make() - { - depCount=$((depCount+1)) - MAKE_PATH=`which make 2>/dev/null` - - if [[ -f $MAKE_PATH ]] - then - depFound=$((depFound+1)) - check "make" - isMake=true - else - uncheck "make is missing" - isMake=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tmake\n" - fi - } - - function find_curl() - { - depCount=$((depCount+1)) - CURL_PATH=`which curl 2>/dev/null` - - if [[ -f $CURL_PATH ]] - then - depFound=$((depFound+1)) - check "curl" - isCurl=true - else - uncheck "curl is missing" - isCurl=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tcurl\n" - fi - } - - function ubuntu1404_rocksdb_installer() - { - sudo apt-get update -qq - sudo apt-get install -qq -y software-properties-common - sudo apt-add-repository -y ppa:giskou/librocksdb - sudo apt-get -f -y install - sudo apt-get update -qq - sudo apt-get install -qq -y librocksdb - } - - function linux_rocksdb_installer() - { - if [[ $isUbuntu1404 == true ]]; then - ubuntu1404_rocksdb_installer - else - oldpwd=`pwd` - cd /tmp - exe git clone --branch v4.2 --depth=1 https://github.com/facebook/rocksdb.git - cd rocksdb - exe make shared_lib - sudo cp -a librocksdb.so* /usr/lib - sudo ldconfig - cd /tmp - rm -rf /tmp/rocksdb - cd $oldpwd - fi - } - - - function verify_installation() { ETH_PATH=`which parity 2>/dev/null` @@ -451,58 +325,32 @@ function run_installer() info "Verifying installation" if [[ $OS_TYPE == "linux" ]]; then - find_curl - find_git - find_make - find_gcc find_rocksdb - find_multirust + find_apt - if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isRocksDB == false || $isMultirustNightly == false ]]; then + if [[ $isRocksDB == false || $isApt == false ]]; then abortInstall fi fi } + function ubuntu_rocksdb_bin_installer() + { + sudo apt-get update -qq + sudo apt-get install -qq -y software-properties-common + sudo apt-add-repository -y ppa:ethcore/ethcore + sudo apt-get -f -y install + sudo apt-get update -qq + sudo apt-get install -qq -y librocksdb + } + function linux_deps_installer() { - if [[ $isGCC == false || $isGit == false || $isMake == false || $isCurl == false ]]; then - info "Installing build dependencies..." - sudo apt-get update -qq - if [[ $isGit == false ]]; then - sudo apt-get install -q -y git - fi - if [[ $isGCC == false ]]; then - sudo apt-get install -q -y g++ gcc - fi - if [[ $isMake == false ]]; then - sudo apt-get install -q -y make - fi - if [[ $isCurl == false ]]; then - sudo apt-get install -q -y curl - fi - echo - fi - if [[ $isRocksDB == false ]]; then - info "Installing rocksdb..." - linux_rocksdb_installer + info "Installing rocksdb binaries..." + ubuntu_rocksdb_bin_installer echo fi - - if [[ $isMultirust == false ]]; then - info "Installing multirust..." - curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes - echo - fi - - if [[ $isMultirustNightly == false ]]; then - info "Installing rust nightly..." - sudo multirust update nightly - sudo multirust default nightly - echo - fi - } function linux_installer() From b1110272a41bfc327eaa75e0e464a495fabfea6d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 9 Feb 2016 12:09:51 +0100 Subject: [PATCH 14/36] Parity install sceipt cleanups. --- install-parity.sh | 157 +++++++++++++++++++++++++++++++--------------- 1 file changed, 108 insertions(+), 49 deletions(-) diff --git a/install-parity.sh b/install-parity.sh index ea0cfc4b6..53a619358 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/beta-0.9/parity_0.9.0-0_amd64.deb +PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/beta-0.9/parity_linux_0.9.0-0_amd64.deb function run_installer() @@ -47,6 +47,7 @@ function run_installer() dim=`tput dim` reverse=`tput rev` reset=`tput sgr0` + n=$'\n' function head() { @@ -94,13 +95,19 @@ function run_installer() ####### Setup methods function wait_for_user() { + if [[ $( ask_user "$1" ) == false ]]; then + abort_install "${red}==>${reset} Process stopped by user. To resume the install run the one-liner command again." + fi + } + + function ask_user() { while : do read -p "${blue}==>${reset} $1 [Y/n] " imp case $imp in - [yY] ) return 0; break ;; - '' ) echo; break ;; - [nN] ) return 1 ;; + [yY] ) echo true; break ;; + '' ) echo true; break ;; + [nN] ) echo false; break ;; * ) echo "Unrecognized option provided. Please provide either 'Y' or 'N'"; esac done @@ -114,11 +121,19 @@ function run_installer() return done } - + function exe() { echo "\$ $@"; "$@" } - + + function sudo() { + if $isSudo; then + `which sudo` "$@" + else + "$@" + fi + } + function detectOS() { if [[ "$OSTYPE" == "linux-gnu" ]] then @@ -130,7 +145,7 @@ function run_installer() get_osx_dependencies else OS_TYPE="win" - abortInstall "${red}==>${reset} ${b}OS not supported:${reset} parity one-liner currently support OS X and Linux.\nFor instructions on installing parity on other platforms please visit ${u}${blue}http://ethcore.io/${reset}" + abortInstall "${red}==>${reset} ${b}OS not supported:${reset} parity one-liner currently support OS X and Linux.${n}For instructions on installing parity on other platforms please visit ${u}${blue}http://ethcore.io/${reset}" fi echo @@ -184,8 +199,8 @@ function run_installer() fi fi - errorMessages+="${red}==>${reset} ${b}Mac OS version too old:${reset} eth requires OS X version ${red}$OSX_REQUIERED_VERSION${reset} at least in order to run.\n" - errorMessages+=" Please update the OS and reload the install process.\n" + errorMessages+="${red}==>${reset} ${b}Mac OS version too old:${reset} eth requires OS X version ${red}$OSX_REQUIERED_VERSION${reset} at least in order to run.${n}" + errorMessages+=" Please update the OS and reload the install process.${n}" } function get_osx_dependencies() @@ -206,11 +221,14 @@ function run_installer() isUbuntu=true else check "Ubuntu, but version not supported" - isUbuntu=false + + errorMessages+="${red}==>${reset} ${b}Ubuntu version not supported:${reset} This script requires Ubuntu version 14.04, 15.04 or 15.10.${n}" + errorMessages+=" Please either upgrade your Ubuntu installation or using the get-deps.ethcore.io script instead, which can help you build Parity.${n}" fi else check "Ubuntu not found" - isUbuntu=false + errorMessages+="${red}==>${reset} ${b}Linux distribution not supported:${reset} This script requires Ubuntu version 14.04, 15.04 or 15.10.${n}" + errorMessages+=" Please either use this on an Ubuntu installation or instead use the get-deps.ethcore.io script, which can help you build Parity.${n}" fi } @@ -218,15 +236,12 @@ function run_installer() { linux_version - find_multirust find_rocksdb find_curl - find_git - find_make - find_gcc find_apt + find_sudo } function find_brew() @@ -242,10 +257,10 @@ function run_installer() uncheck "Homebrew is missing" isBrew=false - INSTALL_FILES+="${blue}${dim}==> Homebrew:${reset}\n" - INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/bin/brew\n" - INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/Library\n" - INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/share/man/man1/brew.1\n" + INSTALL_FILES+="${blue}${dim}==> Homebrew:${reset}${n}" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/bin/brew${n}" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/Library${n}" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/share/man/man1/brew.1${n}" fi depCount=$((depCount+1)) @@ -267,11 +282,57 @@ function run_installer() uncheck "Ruby is missing 🔥" isRuby=false canContinue=false - errorMessages+="${red}==>${reset} ${b}Couldn't find Ruby:${reset} Brew requires Ruby which could not be found.\n" - errorMessages+=" Please install Ruby using these instructions ${u}${blue}https://www.ruby-lang.org/en/documentation/installation/${reset}.\n" + errorMessages+="${red}==>${reset} ${b}Couldn't find Ruby:${reset} Brew requires Ruby which could not be found.${n}" + errorMessages+=" Please install Ruby using these instructions ${u}${blue}https://www.ruby-lang.org/en/documentation/installation/${reset}.${n}" fi } + function find_sudo() + { + depCount=$((depCount+1)) + SUDO_PATH=`which sudo 2>/dev/null` + + if [[ -f $SUDO_PATH ]] + then + depFound=$((depFound+1)) + check "sudo" + isSudo=true + else + uncheck "sudo is missing" + if [[ `whoami` == "root" ]]; then + if [[ $isApt == false && $isMultirust == false ]]; then + canContinue=false + errorMessages+="${red}==>${reset} ${b}Couldn't find sudo:${reset} Sudo is needed for the installation of multirust.${n}" + errorMessages+=" Please ensure you have sudo installed or alternatively install multirust manually.${n}" + fi + + isSudo=false + INSTALL_FILES+="${blue}${dim}==>${reset}\tsudo${n}" + else + canContinue=false + errorMessages+="${red}==>${reset} ${b}Couldn't find sudo:${reset} Root access is needed for parts of this installation.${n}" + errorMessages+=" Please ensure you have sudo installed or alternatively run this script as root.${n}" + fi + fi + } + + function find_curl() + { + depCount=$((depCount+1)) + CURL_PATH=`which curl 2>/dev/null` + + if [[ -f $CURL_PATH ]] + then + depFound=$((depFound+1)) + check "curl" + isCurl=true + else + uncheck "curl is missing" + isCurl=false + INSTALL_FILES+="${blue}${dim}==>${reset}\tcurl${n}" + fi + } + function find_rocksdb() { depCount=$((depCount+1)) @@ -282,7 +343,7 @@ function run_installer() else uncheck "librocksdb is missing" isRocksDB=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tlibrocksdb\n" + INSTALL_FILES+="${blue}${dim}==>${reset}\tlibrocksdb${n}" fi } @@ -302,8 +363,8 @@ function run_installer() isApt=false canContinue=false - errorMessages+="${red}==>${reset} ${b}Couldn't find apt-get:${reset} We can only use apt-get in order to grab our dependencies.\n" - errorMessages+=" Please switch to a distribution such as Debian or Ubuntu or manually install the missing packages.\n" + errorMessages+="${red}==>${reset} ${b}Couldn't find apt-get:${reset} We can only use apt-get in order to grab our dependencies.${n}" + errorMessages+=" Please switch to a distribution such as Debian or Ubuntu or manually install the missing packages.${n}" fi } @@ -334,21 +395,28 @@ function run_installer() fi } - function ubuntu_rocksdb_bin_installer() - { - sudo apt-get update -qq - sudo apt-get install -qq -y software-properties-common - sudo apt-add-repository -y ppa:ethcore/ethcore - sudo apt-get -f -y install - sudo apt-get update -qq - sudo apt-get install -qq -y librocksdb - } - function linux_deps_installer() { + if [[ $isSudo == false ]]; then + info "Installing sudo..." + apt-get install -q -y sudo + echo + fi if [[ $isRocksDB == false ]]; then - info "Installing rocksdb binaries..." - ubuntu_rocksdb_bin_installer + info "Installing rocksdb..." + + sudo apt-get update -qq + sudo apt-get install -qq -y software-properties-common + sudo apt-add-repository -y ppa:ethcore/ethcore + sudo apt-get -f -y install + sudo apt-get update -qq + sudo apt-get install -qq -y librocksdb + + echo + fi + if [[ $isCurl == false ]]; then + info "Installing curl..." + sudo apt-get install -q -y curl echo fi } @@ -361,7 +429,7 @@ function run_installer() info "Installing parity" file=/tmp/parity.deb - wget $PARITY_DEB_URL -qO $file + curl -L $PARITY_DEB_URL > $file sudo dpkg -i $file rm $file } @@ -509,11 +577,9 @@ EOL fi #DEBUG - head "${b}OK,${reset} let's install Parity now!" - if wait_for_user "${b}Last chance!${reset} Sure you want to install this software?" - then + if [[ $(ask_user "${b}Last chance!${reset} Sure you want to install this software?") == true ]]; then install echo echo @@ -521,19 +587,12 @@ EOL finish fi - - - if [[ $OS_TYPE == "linux" ]] - then - echo "Netstats:" - head "Would you like to install and configure a netstats client?" - if wait_for_user "${b}OK,${reset} let's go!" - then + if [[ $OS_TYPE == "linux" && $DISTRIB_ID == "Ubuntu" ]]; then + if [[ $(ask_user "${b}Netstats${reset} Would you like to download, install and configure a Netstats client?${n}${b}${red}WARNING: ${reset}${red}This will need a secret and reconfigure any existing node/NPM installation you have.${reset} ") == true ]]; then install_netstats fi fi - # Display goodbye message finish } From ffadbf1d10ef9463173bad8c0079e5a2d8ec4748 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 9 Feb 2016 12:20:27 +0100 Subject: [PATCH 15/36] Force apt-get update on ubuntu. --- install-parity.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install-parity.sh b/install-parity.sh index 53a619358..02093ca8c 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -397,6 +397,8 @@ function run_installer() function linux_deps_installer() { + sudo apt-get update -qq + if [[ $isSudo == false ]]; then info "Installing sudo..." apt-get install -q -y sudo @@ -405,7 +407,6 @@ function run_installer() if [[ $isRocksDB == false ]]; then info "Installing rocksdb..." - sudo apt-get update -qq sudo apt-get install -qq -y software-properties-common sudo apt-add-repository -y ppa:ethcore/ethcore sudo apt-get -f -y install From 55a29bfa86985122a3a0b8ae4bfcd9038a32aa29 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 03:23:35 -0800 Subject: [PATCH 16/36] unordered verification --- ethcore/src/ethereum/ethash.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 7d99a456a..3e1d7c1bf 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -157,6 +157,11 @@ impl Engine for Ethash { } fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + if header.seal.len() != self.seal_fields() { + return Err(From::from(BlockError::InvalidSealArity( + Mismatch { expected: self.seal_fields(), found: header.seal.len() } + ))); + } let result = self.pow.compute_light(header.number as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64()); let mix = Ethash::from_ethash(result.mix_hash); let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value)); @@ -387,7 +392,32 @@ mod tests { Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, _ => { panic!("should be invalid proof of work error"); } } + } + #[test] + fn can_do_seal_unordered_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let header: Header = Header::default(); + + let verify_result = engine.verify_block_unordered(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + _ => { panic!("should be block seal mismatch error"); } + } + } + + #[test] + fn can_do_seal256_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + let verify_result = engine.verify_block_unordered(&header, None); + + match verify_result { + Err(Error::Block(BlockError::MismatchedH256SealElement(_))) => {}, + _ => { panic!("should be invalid proof of work error"); } + } } // TODO: difficulty test From 5938b6509752998630ff8422a024daf38c7cb340 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 9 Feb 2016 12:24:36 +0100 Subject: [PATCH 17/36] Additional help at he end of the install; no need to install sudo. --- install-parity.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/install-parity.sh b/install-parity.sh index 02093ca8c..60d3471d5 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -397,13 +397,12 @@ function run_installer() function linux_deps_installer() { - sudo apt-get update -qq - - if [[ $isSudo == false ]]; then - info "Installing sudo..." - apt-get install -q -y sudo + if [[ $isRocksDB == false || $isCurl == false ]]; then + info "Preparing apt..." + sudo apt-get update -qq echo fi + if [[ $isRocksDB == false ]]; then info "Installing rocksdb..." @@ -415,6 +414,7 @@ function run_installer() echo fi + if [[ $isCurl == false ]]; then info "Installing curl..." sudo apt-get install -q -y curl @@ -561,8 +561,8 @@ EOL { echo successHeading "All done" - # head "Next steps" - # info "Run ${cyan}\`\`${reset} to get started.${reset}" + head "Next steps" + info "Run ${cyan}\`parity -j\`${reset} to start the Parity Ethereum client.${reset}" echo exit 0 } From 40068c1938ee5569402bd231ff88f6bebc133530 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 12:27:05 +0100 Subject: [PATCH 18/36] added missing docs --- rpc/src/v1/types/bytes.rs | 16 ++++++++++++++++ rpc/src/v1/types/sync.rs | 16 ++++++++++++++++ rpc/src/v1/types/transaction.rs | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 62aca8464..d6a648d7c 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -1,3 +1,19 @@ +// Copyright 2015, 2016 Ethcore (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 rustc_serialize::hex::ToHex; use serde::{Serialize, Serializer}; diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index b13b7167a..595da6032 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -1,3 +1,19 @@ +// Copyright 2015, 2016 Ethcore (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 util::hash::*; #[derive(Default, Debug, Serialize)] diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index de4490cbb..968ec2471 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -1,3 +1,19 @@ +// Copyright 2015, 2016 Ethcore (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 util::hash::*; use util::uint::*; use v1::types::Bytes; From 9358e9444c43c0ee3582e9df414a54200b25c3d6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 03:58:32 -0800 Subject: [PATCH 19/36] unordered h256-pass fix --- ethcore/src/ethereum/ethash.rs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 3e1d7c1bf..0fc22ddfc 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -361,7 +361,8 @@ mod tests { match verify_result { Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, - _ => { panic!("should be block seal mismatch error"); } + Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, } } @@ -375,7 +376,8 @@ mod tests { match verify_result { Err(Error::Block(BlockError::DifficultyOutOfBounds(_))) => {}, - _ => { panic!("should be block difficulty error"); } + Err(_) => { panic!("should be block difficulty error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, } } @@ -390,7 +392,8 @@ mod tests { match verify_result { Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, - _ => { panic!("should be invalid proof of work error"); } + Err(_) => { panic!("should be invalid proof of work error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, } } @@ -403,7 +406,8 @@ mod tests { match verify_result { Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, - _ => { panic!("should be block seal mismatch error"); } + Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, } } @@ -416,10 +420,28 @@ mod tests { match verify_result { Err(Error::Block(BlockError::MismatchedH256SealElement(_))) => {}, - _ => { panic!("should be invalid proof of work error"); } + Err(_) => { panic!("should be invalid 256-bit seal fail (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, } } + #[test] + fn can_do_proof_of_work_unordered_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); + + let verify_result = engine.verify_block_unordered(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + Err(_) => { panic!("should be invalid proof-of-work fail (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + + } + // TODO: difficulty test } From 095c60d440d9fbad1dc0009fd9800a2cce907e75 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 04:20:18 -0800 Subject: [PATCH 20/36] possible panic resolution, block family tests --- ethcore/src/ethereum/ethash.rs | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 0fc22ddfc..e931080b2 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -175,6 +175,11 @@ impl Engine for Ethash { } fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + // we should not calculate difficulty for genesis blocks + if header.number() == 0 { + return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))); + } + // Check difficulty is correct given the two timestamps. let expected_difficulty = self.calculate_difficuty(header, parent); if header.difficulty != expected_difficulty { @@ -439,7 +444,56 @@ mod tests { Err(_) => { panic!("should be invalid proof-of-work fail (got {:?})", verify_result); }, _ => { panic!("Should be error, got Ok"); }, } + } + #[test] + fn can_verify_block_family_genesis_fail() { + let engine = Ethash::new_test(new_morden()); + let header: Header = Header::default(); + let parent_header: Header = Header::default(); + + let verify_result = engine.verify_block_family(&header, &parent_header, None); + + match verify_result { + Err(Error::Block(BlockError::RidiculousNumber(_))) => {}, + Err(_) => { panic!("should be invalid block number fail (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_verify_block_family_difficulty_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_number(2); + let mut parent_header: Header = Header::default(); + parent_header.set_number(1); + + let verify_result = engine.verify_block_family(&header, &parent_header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidDifficulty(_))) => {}, + Err(_) => { panic!("should be invalid difficulty fail (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_verify_block_family_gas_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_number(2); + header.set_difficulty(U256::from_str("0000000000000000000000000000000000000000000000000000000000020000").unwrap()); + let mut parent_header: Header = Header::default(); + parent_header.set_number(1); + + let verify_result = engine.verify_block_family(&header, &parent_header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidGasLimit(_))) => {}, + Err(_) => { panic!("should be invalid difficulty fail (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } } // TODO: difficulty test From fd18be4317f05f2fcc38eba7e187b64431bdd611 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 13:21:32 +0100 Subject: [PATCH 21/36] change CLIENT_DB_VER_STR instead of DB_VERSION --- ethcore/src/client.rs | 2 +- util/src/journaldb.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index b31f98f0b..11671b3f2 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -164,7 +164,7 @@ pub struct Client { } const HISTORY: u64 = 1000; -const CLIENT_DB_VER_STR: &'static str = "1.0"; +const CLIENT_DB_VER_STR: &'static str = "2.0"; impl Client { /// Create a new client with given spec and DB path. diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 28dcacbfa..d9d7b29cf 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -50,7 +50,7 @@ impl Clone for JournalDB { const LAST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; const VERSION_KEY : [u8; 4] = [ b'j', b'v', b'e', b'r' ]; -const DB_VERSION: u32 = 2; +const DB_VERSION: u32 = 1; impl JournalDB { /// Create a new instance given a `backing` database. From cc4206f6902cf6e644004656b133d1e2d368acdf Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 06:28:27 -0800 Subject: [PATCH 22/36] initial test setup --- ethcore/src/externalities.rs | 70 +++++++++++++++++++++++++++++------- ethcore/src/substate.rs | 6 ++++ 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index ad2f18f11..282254dae 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -68,12 +68,12 @@ pub struct Externalities<'a> { impl<'a> Externalities<'a> { /// Basic `Externalities` constructor. - pub fn new(state: &'a mut State, - env_info: &'a EnvInfo, - engine: &'a Engine, + pub fn new(state: &'a mut State, + env_info: &'a EnvInfo, + engine: &'a Engine, depth: usize, origin_info: OriginInfo, - substate: &'a mut Substate, + substate: &'a mut Substate, output: OutputPolicy<'a>) -> Self { Externalities { state: state, @@ -139,7 +139,7 @@ impl<'a> Ext for Externalities<'a> { self.state.inc_nonce(&self.origin_info.address); let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); - + // TODO: handle internal error separately match ex.create(params, self.substate) { Ok(gas_left) => { @@ -150,18 +150,18 @@ impl<'a> Ext for Externalities<'a> { } } - fn call(&mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, + fn call(&mut self, + gas: &U256, + sender_address: &Address, + receive_address: &Address, value: Option, - data: &[u8], - code_address: &Address, + data: &[u8], + code_address: &Address, output: &mut [u8]) -> MessageCallResult { let mut params = ActionParams { sender: sender_address.clone(), - address: receive_address.clone(), + address: receive_address.clone(), value: ActionValue::Apparent(self.origin_info.value.clone()), code_address: code_address.clone(), origin: self.origin_info.origin.clone(), @@ -257,3 +257,49 @@ impl<'a> Ext for Externalities<'a> { self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one(); } } + +#[cfg(test)] +mod tests { + use common::*; + use state::*; + use engine::*; + use executive::*; + use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult}; + use substate::*; + use tests::helpers::*; + use super::*; + + fn get_test_origin() -> OriginInfo { + OriginInfo { + address: Address::zero(), + origin: Address::zero(), + gas_price: U256::zero(), + value: U256::zero() + } + } + + fn get_test_env_info() -> EnvInfo { + EnvInfo { + number: 100, + author: x!(0), + timestamp: 0, + difficulty: x!(0), + last_hashes: vec![], + gas_used: x!(0), + gas_limit: x!(0) + } + } + + #[test] + fn can_be_created() { + let mut state_result = get_temp_state(); + let state = state_result.reference_mut(); + let test_spec = get_test_spec(); + let test_engine: &Engine = &*test_spec.to_engine().unwrap(); + let mut test_sub_state = Substate::new(); + let env_info = get_test_env_info(); + + let ext = Externalities::new(state, &env_info, test_engine, 0, get_test_origin(), &mut test_sub_state, OutputPolicy::InitContract); + } + +} diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index f42ea38fd..9f9f5c1df 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -56,6 +56,12 @@ mod tests { use super::*; use common::*; + #[test] + fn created() { + let mut sub_state = Substate::new(); + assert_eq!(sub_state.suicides.len(), 0); + } + #[test] fn accrue() { let mut sub_state = Substate::new(); From e987a492dc952ff458b697925ef4dcc7d296f2e6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 9 Feb 2016 15:51:48 +0100 Subject: [PATCH 23/36] --chain option for setting which network to go on. Add contents function to util. --- Cargo.toml | 1 + parity/main.rs | 38 ++++++++++++++++++++++++++++++++------ util/src/misc.rs | 9 +++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1eac83ac3..836967631 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ ethcore = { path = "ethcore" } ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } +target_info = "0.1" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index d423caa64..43a249886 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -29,6 +29,7 @@ extern crate log as rlog; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; +extern crate target_info; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -39,23 +40,25 @@ use rlog::{LogLevelFilter}; use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; +use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; +use target_info::Target; docopt!(Args derive Debug, " Parity. Ethereum Client. + By Wood/Paronyan/Kotewicz/Drwięga/Volf. + Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity [options] - parity [options] ... + parity [options] [ ... ] Options: - -l --logging LOGGING Specify the logging level. - -j --jsonrpc Enable the JSON-RPC API sever. - --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. + --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file + or frontier, mainnet, morden, or testnet [default: frontier]. --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304]. @@ -64,6 +67,11 @@ Options: --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. + -j --jsonrpc Enable the JSON-RPC API sever. + --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. + + -l --logging LOGGING Specify the logging level. + -v --version Show information about version. -h --help Show this screen. ", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option); @@ -100,10 +108,28 @@ fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) { fn main() { let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit()); + if args.flag_version { + println!(" +Parity version {} ({}-{}-{}) +Copyright 2015, 2016 Ethcore (UK) Limited +License GPLv3+: GNU GPL version 3 or later . +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +By Wood/Paronyan/Kotewicz/Drwięga/Volf. +", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()); + return; + } + setup_log(&args.flag_logging); unsafe { ::fdlimit::raise_fd_limit(); } - let spec = ethereum::new_frontier(); + let spec = match args.flag_chain.as_ref() { + "frontier" | "mainnet" => ethereum::new_frontier(), + "morden" | "testnet" => ethereum::new_morden(), + "olympic" => ethereum::new_olympic(), + f => Spec::from_json_utf8(contents(f).expect("Couldn't read chain specification file. Sure it exists?").as_ref()), + }; let init_nodes = match args.arg_enode.len() { 0 => spec.nodes().clone(), _ => args.arg_enode.clone(), diff --git a/util/src/misc.rs b/util/src/misc.rs index 43027015e..6e2240d33 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -16,6 +16,7 @@ //! Diff misc. +use std::fs::File; use common::*; #[derive(Debug,Clone,PartialEq,Eq)] @@ -53,3 +54,11 @@ pub enum Filth { /// Data has been changed. Dirty, } + +/// Read the whole contents of a file `name`. +pub fn contents(name: &str) -> Result { + let mut file = try!(File::open(name)); + let mut ret: Vec = Vec::new(); + try!(file.read_to_end(&mut ret)); + Ok(ret) +} From 8be5340385f72a4b7fa8c60f6028cfe84fb61934 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 9 Feb 2016 16:19:12 +0100 Subject: [PATCH 24/36] Tabs! --- util/src/misc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/misc.rs b/util/src/misc.rs index 6e2240d33..ae3dbc5bf 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -58,7 +58,7 @@ pub enum Filth { /// Read the whole contents of a file `name`. pub fn contents(name: &str) -> Result { let mut file = try!(File::open(name)); - let mut ret: Vec = Vec::new(); - try!(file.read_to_end(&mut ret)); - Ok(ret) + let mut ret: Vec = Vec::new(); + try!(file.read_to_end(&mut ret)); + Ok(ret) } From 7f607905ed1270f8bd640ca28169cf9843615e76 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 07:31:57 -0800 Subject: [PATCH 25/36] moving around setups --- ethcore/src/executive.rs | 92 ++++++++++++------------------------ ethcore/src/externalities.rs | 17 +++++++ ethcore/src/tests/helpers.rs | 33 ++++++++++++- 3 files changed, 79 insertions(+), 63 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 812dc3acd..782063cb2 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -43,11 +43,11 @@ pub struct Executed { pub gas: U256, /// Gas used during execution of transaction. pub gas_used: U256, - /// Gas refunded after the execution of transaction. + /// Gas refunded after the execution of transaction. /// To get gas that was required up front, add `refunded` and `gas_used`. pub refunded: U256, /// Cumulative gas used in current block so far. - /// + /// /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` /// /// where `tn` is current transaction. @@ -56,9 +56,9 @@ pub struct Executed { pub logs: Vec, /// Addresses of contracts created during execution of transaction. /// Ordered from earliest creation. - /// - /// eg. sender creates contract A and A in constructor creates contract B - /// + /// + /// eg. sender creates contract A and A in constructor creates contract B + /// /// B creation ends first, and it will be the first element of the vector. pub contracts_created: Vec
} @@ -119,13 +119,13 @@ impl<'a> Executive<'a> { if t.nonce != nonce { return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); } - + // validate if transaction fits into given block if self.info.gas_used + t.gas > self.info.gas_limit { - return Err(From::from(ExecutionError::BlockGasLimitReached { - gas_limit: self.info.gas_limit, - gas_used: self.info.gas_used, - gas: t.gas + return Err(From::from(ExecutionError::BlockGasLimitReached { + gas_limit: self.info.gas_limit, + gas_used: self.info.gas_used, + gas: t.gas })); } @@ -220,7 +220,7 @@ impl<'a> Executive<'a> { if self.engine.is_builtin(¶ms.code_address) { // if destination is builtin, try to execute it - + let default = []; let data = if let Some(ref d) = params.data { d as &[u8] } else { &default as &[u8] }; @@ -239,7 +239,7 @@ impl<'a> Executive<'a> { } } else if params.code.is_some() { // if destination is a contract, do normal message call - + // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(); @@ -258,7 +258,7 @@ impl<'a> Executive<'a> { Ok(params.gas) } } - + /// Creates contract with given contract params. /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate. @@ -317,7 +317,7 @@ impl<'a> Executive<'a> { self.state.kill_account(address); } - match result { + match result { Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(_) => { Ok(Executed { @@ -345,8 +345,8 @@ impl<'a> Executive<'a> { fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) { match *result { Err(evm::Error::OutOfGas) - | Err(evm::Error::BadJumpDestination {..}) - | Err(evm::Error::BadInstruction {.. }) + | Err(evm::Error::BadJumpDestination {..}) + | Err(evm::Error::BadInstruction {.. }) | Err(evm::Error::StackUnderflow {..}) | Err(evm::Error::OutOfStack {..}) => { self.state.revert_snapshot(); @@ -364,42 +364,10 @@ impl<'a> Executive<'a> { mod tests { use super::*; use common::*; - use ethereum; - use engine::*; - use spec::*; - use evm::{Schedule, Factory, VMType}; + use evm::{Factory, VMType}; use substate::*; use tests::helpers::*; - struct TestEngine { - factory: Factory, - spec: Spec, - max_depth: usize - } - - impl TestEngine { - fn new(max_depth: usize, factory: Factory) -> TestEngine { - TestEngine { - factory: factory, - spec: ethereum::new_frontier_test(), - max_depth: max_depth - } - } - } - - impl Engine for TestEngine { - fn name(&self) -> &str { "TestEngine" } - fn spec(&self) -> &Spec { &self.spec } - fn vm_factory(&self) -> &Factory { - &self.factory - } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { - let mut schedule = Schedule::new_frontier(); - schedule.max_depth = self.max_depth; - schedule - } - } - #[test] fn test_contract_address() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); @@ -488,7 +456,7 @@ mod tests { let mut ex = Executive::new(&mut state, &info, &engine); ex.create(params, &mut substate).unwrap() }; - + assert_eq!(gas_left, U256::from(62_976)); // ended with max depth assert_eq!(substate.contracts_created.len(), 0); @@ -542,7 +510,7 @@ mod tests { let mut ex = Executive::new(&mut state, &info, &engine); ex.create(params, &mut substate).unwrap() }; - + assert_eq!(gas_left, U256::from(62_976)); assert_eq!(substate.contracts_created.len(), 0); } @@ -594,7 +562,7 @@ mod tests { let mut ex = Executive::new(&mut state, &info, &engine); ex.create(params, &mut substate).unwrap(); } - + assert_eq!(substate.contracts_created.len(), 1); assert_eq!(substate.contracts_created[0], next_address); } @@ -666,7 +634,7 @@ mod tests { fn test_recursive_bomb1(factory: Factory) { // 60 01 - push 1 // 60 00 - push 0 - // 54 - sload + // 54 - sload // 01 - add // 60 00 - push 0 // 55 - sstore @@ -766,7 +734,7 @@ mod tests { let mut ex = Executive::new(&mut state, &info, &engine); ex.transact(&t) }; - + match res { Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) => (), _ => assert!(false, "Expected invalid signature error.") @@ -797,10 +765,10 @@ mod tests { let mut ex = Executive::new(&mut state, &info, &engine); ex.transact(&t) }; - + match res { - Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) - if expected == U256::zero() && got == U256::one() => (), + Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) + if expected == U256::zero() && got == U256::one() => (), _ => assert!(false, "Expected invalid nonce error.") } } @@ -832,8 +800,8 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) - if gas_limit == U256::from(100_000) && gas_used == U256::from(20_000) && gas == U256::from(80_001) => (), + Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) + if gas_limit == U256::from(100_000) && gas_used == U256::from(20_000) && gas == U256::from(80_001) => (), _ => assert!(false, "Expected block gas limit error.") } } @@ -863,10 +831,10 @@ mod tests { let mut ex = Executive::new(&mut state, &info, &engine); ex.transact(&t) }; - + match res { - Err(Error::Execution(ExecutionError::NotEnoughCash { required , got })) - if required == U512::from(100_018) && got == U512::from(100_017) => (), + Err(Error::Execution(ExecutionError::NotEnoughCash { required , got })) + if required == U512::from(100_018) && got == U512::from(100_017) => (), _ => assert!(false, "Expected not enough cash error. {:?}", res) } } diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 282254dae..29249709b 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -300,6 +300,23 @@ mod tests { let env_info = get_test_env_info(); let ext = Externalities::new(state, &env_info, test_engine, 0, get_test_origin(), &mut test_sub_state, OutputPolicy::InitContract); + + assert_eq!(ext.env_info().number, 100); + } + + #[test] + fn can_return_block_hash() { + let mut state_result = get_temp_state(); + let state = state_result.reference_mut(); + let test_spec = get_test_spec(); + let test_engine: &Engine = &*test_spec.to_engine().unwrap(); + let mut test_sub_state = Substate::new(); + let env_info = get_test_env_info(); + + let ext = Externalities::new(state, &env_info, test_engine, 0, get_test_origin(), &mut test_sub_state, OutputPolicy::InitContract); + + let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); + assert_eq!(hash, H256::zero()); } } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index f5815b718..93e3e0a0d 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -23,7 +23,9 @@ use std::fs::{remove_dir_all}; use blockchain::{BlockChain}; use state::*; use rocksdb::*; - +use evm::{Schedule, Factory}; +use engine::*; +use ethereum; #[cfg(feature = "json-tests")] pub enum ChainEra { @@ -81,6 +83,35 @@ impl GuardedTempResult { } } +pub struct TestEngine { + factory: Factory, + spec: Spec, + max_depth: usize +} + +impl TestEngine { + pub fn new(max_depth: usize, factory: Factory) -> TestEngine { + TestEngine { + factory: factory, + spec: ethereum::new_frontier_test(), + max_depth: max_depth + } + } +} + +impl Engine for TestEngine { + fn name(&self) -> &str { "TestEngine" } + fn spec(&self) -> &Spec { &self.spec } + fn vm_factory(&self) -> &Factory { + &self.factory + } + fn schedule(&self, _env_info: &EnvInfo) -> Schedule { + let mut schedule = Schedule::new_frontier(); + schedule.max_depth = self.max_depth; + schedule + } +} + pub fn get_test_spec() -> Spec { Spec::new_test() } From b42f5145a639a121e37dbdf8f10c8ef53f5044e2 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 07:54:58 -0800 Subject: [PATCH 26/36] check env_info --- ethcore/src/externalities.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 29249709b..4cc697eb1 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -106,16 +106,18 @@ impl<'a> Ext for Externalities<'a> { } fn blockhash(&self, number: &U256) -> H256 { + // TODO: comment out what this function expects from env_info, since it will produce panics if the latter is inconsistent match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 { true => { let index = self.env_info.number - number.low_u64() - 1; + assert!(index < self.env_info.last_hashes.len() as u64, format!("Inconsistent env_info, should contain at least {:?} last hashes", index+1)); let r = self.env_info.last_hashes[index as usize].clone(); trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number); r }, false => { trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number); - H256::from(&U256::zero()) + H256::zero() }, } } @@ -305,7 +307,7 @@ mod tests { } #[test] - fn can_return_block_hash() { + fn can_return_block_hash_no_env() { let mut state_result = get_temp_state(); let state = state_result.reference_mut(); let test_spec = get_test_spec(); @@ -319,4 +321,22 @@ mod tests { assert_eq!(hash, H256::zero()); } + #[test] + fn can_return_block_hash() { + let mut state_result = get_temp_state(); + let state = state_result.reference_mut(); + let test_spec = get_test_spec(); + let test_engine: &Engine = &*test_spec.to_engine().unwrap(); + let mut test_sub_state = Substate::new(); + let mut env_info = get_test_env_info(); + env_info.number = 0x120001; + let test_hash = H256::from("afafafafafafafafafafafbcbcbcbcbcbcbcbcbcbeeeeeeeeeeeeedddddddddd"); + env_info.last_hashes.push(test_hash.clone()); + + let ext = Externalities::new(state, &env_info, test_engine, 0, get_test_origin(), &mut test_sub_state, OutputPolicy::InitContract); + + let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); + assert_eq!(test_hash, hash); + } + } From d8f8038f16ba4e8f5f04b997537d0d87854ae6b9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 9 Feb 2016 17:23:25 +0100 Subject: [PATCH 27/36] Additional tweaks to options. --- parity/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 43a249886..f5a07208e 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -109,14 +109,14 @@ fn main() { let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit()); if args.flag_version { - println!(" + println!("\ Parity version {} ({}-{}-{}) Copyright 2015, 2016 Ethcore (UK) Limited License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. -By Wood/Paronyan/Kotewicz/Drwięga/Volf. +By Wood/Paronyan/Kotewicz/Drwięga/Volf.\ ", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()); return; } From 5767931df638f5cd64cc9476388178ea62b745d0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 19:29:52 +0300 Subject: [PATCH 28/36] dried out tests --- ethcore/src/externalities.rs | 68 +++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 4cc697eb1..2593c3ce7 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -270,6 +270,7 @@ mod tests { use substate::*; use tests::helpers::*; use super::*; + use spec::*; fn get_test_origin() -> OriginInfo { OriginInfo { @@ -292,51 +293,70 @@ mod tests { } } + struct TestSetup { + state: GuardedTempResult, + spec: Spec, + engine: Box, + sub_state: Substate, + env_info: EnvInfo + } + + impl TestSetup { + fn new() -> TestSetup { + let spec = get_test_spec(); + TestSetup { + state: get_temp_state(), + spec: get_test_spec(), + engine: spec.to_engine().unwrap(), + sub_state: Substate::new(), + env_info: get_test_env_info() + } + } + } + #[test] fn can_be_created() { - let mut state_result = get_temp_state(); - let state = state_result.reference_mut(); - let test_spec = get_test_spec(); - let test_engine: &Engine = &*test_spec.to_engine().unwrap(); - let mut test_sub_state = Substate::new(); - let env_info = get_test_env_info(); + let mut setup = TestSetup::new(); + let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &env_info, test_engine, 0, get_test_origin(), &mut test_sub_state, OutputPolicy::InitContract); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); assert_eq!(ext.env_info().number, 100); } #[test] fn can_return_block_hash_no_env() { - let mut state_result = get_temp_state(); - let state = state_result.reference_mut(); - let test_spec = get_test_spec(); - let test_engine: &Engine = &*test_spec.to_engine().unwrap(); - let mut test_sub_state = Substate::new(); - let env_info = get_test_env_info(); - - let ext = Externalities::new(state, &env_info, test_engine, 0, get_test_origin(), &mut test_sub_state, OutputPolicy::InitContract); + let mut setup = TestSetup::new(); + let state = setup.state.reference_mut(); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); + assert_eq!(hash, H256::zero()); } #[test] fn can_return_block_hash() { - let mut state_result = get_temp_state(); - let state = state_result.reference_mut(); - let test_spec = get_test_spec(); - let test_engine: &Engine = &*test_spec.to_engine().unwrap(); - let mut test_sub_state = Substate::new(); - let mut env_info = get_test_env_info(); - env_info.number = 0x120001; let test_hash = H256::from("afafafafafafafafafafafbcbcbcbcbcbcbcbcbcbeeeeeeeeeeeeedddddddddd"); - env_info.last_hashes.push(test_hash.clone()); + let test_env_number = 0x120001; - let ext = Externalities::new(state, &env_info, test_engine, 0, get_test_origin(), &mut test_sub_state, OutputPolicy::InitContract); + let mut setup = TestSetup::new(); + { + let env_info = &mut setup.env_info; + env_info.number = test_env_number; + env_info.last_hashes.push(test_hash.clone()); + } + let state = setup.state.reference_mut(); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); + assert_eq!(test_hash, hash); } + #[test] + fn can_call_fail() { + let setup = TestSetup::new(); + } + } From 1603b2bf642254dae56c5b7399e9dd22cc0a37e4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 19:47:14 +0300 Subject: [PATCH 29/36] flush --- ethcore/src/externalities.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 2593c3ce7..2bf784134 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -357,6 +357,8 @@ mod tests { #[test] fn can_call_fail() { let setup = TestSetup::new(); + let state = setup.state.reference_mut(); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); } } From 3b01ca93cd446aa54496ed51c69857f2a5daf826 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 9 Feb 2016 22:30:35 +0300 Subject: [PATCH 30/36] call fail test --- ethcore/src/externalities.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 2bf784134..b5a0c2539 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -355,10 +355,24 @@ mod tests { } #[test] - fn can_call_fail() { - let setup = TestSetup::new(); + fn can_call_fail_empty() { + let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); - } + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let mut output = vec![]; + + let result = ext.call( + &U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap(), + &Address::new(), + &Address::new(), + Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()), + &vec![], + &Address::new(), + &mut output); + + if let MessageCallResult::Success(_) = result { + panic!("Call should have failed because no data was provided"); + } + } } From 71786dd1721ca028297357f4ca20bf510e421516 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 10 Feb 2016 00:32:47 +0300 Subject: [PATCH 31/36] should_panic test --- ethcore/src/account.rs | 10 +++++++--- ethcore/src/externalities.rs | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index aa5a0c4bd..c36c35232 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -183,11 +183,11 @@ impl Account { #[cfg(test)] /// Determine whether there are any un-`commit()`-ed storage-setting operations. pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() } - + #[cfg(test)] /// return the storage root associated with this account or None if it has been altered via the overlay. pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} } - + /// return the storage overlay. pub fn storage_overlay(&self) -> Ref> { self.storage_overlay.borrow() } @@ -198,7 +198,11 @@ impl Account { pub fn add_balance(&mut self, x: &U256) { self.balance = self.balance + *x; } /// Increment the nonce of the account by one. - pub fn sub_balance(&mut self, x: &U256) { self.balance = self.balance - *x; } + /// Panics if balance is less than `x` + pub fn sub_balance(&mut self, x: &U256) { + assert!(self.balance >= *x); + self.balance = self.balance - *x; + } /// Commit the `storage_overlay` to the backing DB and update `storage_root`. pub fn commit_storage(&mut self, db: &mut AccountDBMut) { diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index b5a0c2539..20c0222d2 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -355,6 +355,7 @@ mod tests { } #[test] + #[should_panic] fn can_call_fail_empty() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); From 2b6eb97f6636831b63acb22b5517c770c8b65cdb Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 10 Feb 2016 00:41:45 +0300 Subject: [PATCH 32/36] log test --- ethcore/src/externalities.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 20c0222d2..b63989944 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -376,4 +376,20 @@ mod tests { panic!("Call should have failed because no data was provided"); } } + + #[test] + fn can_log() { + let log_data = vec![120u8, 110u8]; + let log_topics = vec![H256::from("afafafafafafafafafafafbcbcbcbcbcbcbcbcbcbeeeeeeeeeeeeedddddddddd")]; + + let mut setup = TestSetup::new(); + let state = setup.state.reference_mut(); + + { + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + ext.log(log_topics, &log_data); + } + + assert_eq!(setup.sub_state.logs.len(), 1); + } } From 2982c7973e7d9a34dcc72883005584d8b5781ab5 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 10 Feb 2016 01:02:31 +0300 Subject: [PATCH 33/36] externalities suicide test --- ethcore/src/externalities.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index b63989944..c1357ea5e 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -363,24 +363,21 @@ mod tests { let mut output = vec![]; - let result = ext.call( + // this should panic because we have no balance on any account + ext.call( &U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap(), &Address::new(), &Address::new(), - Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()), + Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000150000").unwrap()), &vec![], &Address::new(), &mut output); - - if let MessageCallResult::Success(_) = result { - panic!("Call should have failed because no data was provided"); - } } #[test] fn can_log() { let log_data = vec![120u8, 110u8]; - let log_topics = vec![H256::from("afafafafafafafafafafafbcbcbcbcbcbcbcbcbcbeeeeeeeeeeeeedddddddddd")]; + let log_topics = vec![H256::from("af0fa234a6af46afa23faf23bcbc1c1cb4bcb7bcbe7e7e7ee3ee2edddddddddd")]; let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); @@ -392,4 +389,19 @@ mod tests { assert_eq!(setup.sub_state.logs.len(), 1); } + + #[test] + fn can_suicide() { + let refund_account = &Address::new(); + + let mut setup = TestSetup::new(); + let state = setup.state.reference_mut(); + + { + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + ext.suicide(&refund_account); + } + + assert_eq!(setup.sub_state.suicides.len(), 1); + } } From dabce9ab45f3eda2bf8bc34b211bd0ac134f573c Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 10 Feb 2016 01:11:22 +0300 Subject: [PATCH 34/36] cleanup, warnings --- ethcore/src/externalities.rs | 9 ++------- ethcore/src/substate.rs | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index c1357ea5e..558e477c7 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -265,12 +265,10 @@ mod tests { use common::*; use state::*; use engine::*; - use executive::*; - use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult}; + use evm::{Ext}; use substate::*; use tests::helpers::*; use super::*; - use spec::*; fn get_test_origin() -> OriginInfo { OriginInfo { @@ -295,7 +293,6 @@ mod tests { struct TestSetup { state: GuardedTempResult, - spec: Spec, engine: Box, sub_state: Substate, env_info: EnvInfo @@ -303,11 +300,9 @@ mod tests { impl TestSetup { fn new() -> TestSetup { - let spec = get_test_spec(); TestSetup { state: get_temp_state(), - spec: get_test_spec(), - engine: spec.to_engine().unwrap(), + engine: get_test_spec().to_engine().unwrap(), sub_state: Substate::new(), env_info: get_test_env_info() } diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 9f9f5c1df..235ce2e97 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -58,7 +58,7 @@ mod tests { #[test] fn created() { - let mut sub_state = Substate::new(); + let sub_state = Substate::new(); assert_eq!(sub_state.suicides.len(), 0); } From 4ab99a6bb3d0b58f79d16b1a4815c6aaecfa6f4c Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 10 Feb 2016 02:20:36 +0300 Subject: [PATCH 35/36] fixed conflicting namespaces --- ethcore/src/json_tests/executive.rs | 62 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 7ac60e6b4..b08257a92 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -26,29 +26,29 @@ use externalities::*; use substate::*; use tests::helpers::*; -struct TestEngine { +struct TestEngineFrontier { vm_factory: Factory, spec: Spec, max_depth: usize } -impl TestEngine { - fn new(max_depth: usize, vm_type: VMType) -> TestEngine { - TestEngine { +impl TestEngineFrontier { + fn new(max_depth: usize, vm_type: VMType) -> TestEngineFrontier { + TestEngineFrontier { vm_factory: Factory::new(vm_type), spec: ethereum::new_frontier_test(), - max_depth: max_depth + max_depth: max_depth } } } -impl Engine for TestEngine { +impl Engine for TestEngineFrontier { fn name(&self) -> &str { "TestEngine" } fn spec(&self) -> &Spec { &self.spec } fn vm_factory(&self) -> &Factory { &self.vm_factory } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { + fn schedule(&self, _env_info: &EnvInfo) -> Schedule { let mut schedule = Schedule::new_frontier(); - schedule.max_depth = self.max_depth; + schedule.max_depth = self.max_depth; schedule } } @@ -69,12 +69,12 @@ struct TestExt<'a> { } impl<'a> TestExt<'a> { - fn new(state: &'a mut State, - info: &'a EnvInfo, - engine: &'a Engine, + fn new(state: &'a mut State, + info: &'a EnvInfo, + engine: &'a Engine, depth: usize, origin_info: OriginInfo, - substate: &'a mut Substate, + substate: &'a mut Substate, output: OutputPolicy<'a>, address: Address) -> Self { TestExt { @@ -116,13 +116,13 @@ impl<'a> Ext for TestExt<'a> { ContractCreateResult::Created(self.contract_address.clone(), *gas) } - fn call(&mut self, - gas: &U256, - _sender_address: &Address, - receive_address: &Address, + fn call(&mut self, + gas: &U256, + _sender_address: &Address, + receive_address: &Address, value: Option, - data: &[u8], - _code_address: &Address, + data: &[u8], + _code_address: &Address, _output: &mut [u8]) -> MessageCallResult { self.callcreates.push(CallCreate { data: data.to_vec(), @@ -136,7 +136,7 @@ impl<'a> Ext for TestExt<'a> { fn extcode(&self, address: &Address) -> Bytes { self.ext.extcode(address) } - + fn log(&mut self, topics: Vec, data: &[u8]) { self.ext.log(topics, data) } @@ -185,11 +185,11 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { // ::std::io::stdout().flush(); let mut fail = false; //let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); fail = true }; - let mut fail_unless = |cond: bool, s: &str | if !cond && !fail { - failed.push(format!("[{}] {}: {}", vm, name, s)); - fail = true + let mut fail_unless = |cond: bool, s: &str | if !cond && !fail { + failed.push(format!("[{}] {}: {}", vm, name, s)); + fail = true }; - + // test env let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); @@ -209,7 +209,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { EnvInfo::from_json(env) }).unwrap_or_default(); - let engine = TestEngine::new(1, vm.clone()); + let engine = TestEngineFrontier::new(1, vm.clone()); // params let mut params = ActionParams::default(); @@ -226,18 +226,18 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { let out_of_gas = test.find("callcreates").map(|_calls| { }).is_none(); - + let mut substate = Substate::new(); let mut output = vec![]; // execute let (res, callcreates) = { - let mut ex = TestExt::new(&mut state, - &info, - &engine, - 0, - OriginInfo::from(¶ms), - &mut substate, + let mut ex = TestExt::new(&mut state, + &info, + &engine, + 0, + OriginInfo::from(¶ms), + &mut substate, OutputPolicy::Return(BytesRef::Flexible(&mut output)), params.address.clone()); let evm = engine.vm_factory().create(); From 92a08c26ade5ae8714f0c5c6f3806630f9538deb Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 10 Feb 2016 03:27:54 +0300 Subject: [PATCH 36/36] excluding test code itself from coverage --- .travis.yml | 10 +++++----- cov.sh | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 227853669..675eb0be1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,11 +37,11 @@ after_success: | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && cargo test --no-run ${KCOV_FEATURES} ${TARGETS} && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethcore_util-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethash-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethcore-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethsync-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/deps/ethcore_rpc-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && diff --git a/cov.sh b/cov.sh index c63687acf..a1fa29e46 100755 --- a/cov.sh +++ b/cov.sh @@ -18,9 +18,9 @@ fi cargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --no-run || exit $? rm -rf target/coverage mkdir -p target/coverage -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethash-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethsync-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* +kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore-* +kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethash-* +kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* +kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethsync-* +kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* xdg-open target/coverage/index.html