Merge branch 'master' into on-demand-priority

This commit is contained in:
Robert Habermeier 2017-04-13 16:44:47 +02:00
commit a98052fe74
72 changed files with 1013 additions and 1222 deletions

6
Cargo.lock generated
View File

@ -784,8 +784,7 @@ name = "ethstore"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.7.0", "ethcore-bigint 0.1.2",
"ethcore-util 1.7.0",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -800,6 +799,7 @@ dependencies = [
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1761,7 +1761,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-ui-precompiled" name = "parity-ui-precompiled"
version = "1.4.0" version = "1.4.0"
source = "git+https://github.com/paritytech/js-precompiled.git#b4c41885c6e02c64fb773546b2f135f56ea7022f" source = "git+https://github.com/paritytech/js-precompiled.git#fb346e5f2925d1b2d533eb986bd2cefb962c7a88"
dependencies = [ dependencies = [
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -61,6 +61,7 @@ impl Default for CacheSizes {
/// ///
/// Note that almost all getter methods take `&mut self` due to the necessity to update /// Note that almost all getter methods take `&mut self` due to the necessity to update
/// the underlying LRU-caches on read. /// the underlying LRU-caches on read.
/// [LRU-cache](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29)
pub struct Cache { pub struct Cache {
headers: MemoryLruCache<H256, encoded::Header>, headers: MemoryLruCache<H256, encoded::Header>,
canon_hashes: MemoryLruCache<BlockNumber, H256>, canon_hashes: MemoryLruCache<BlockNumber, H256>,

View File

@ -15,7 +15,7 @@
//! //!
//! Each CHT is a trie mapping block numbers to canonical hashes and total difficulty. //! Each CHT is a trie mapping block numbers to canonical hashes and total difficulty.
//! One is generated for every `SIZE` blocks, allowing us to discard those blocks in //! One is generated for every `SIZE` blocks, allowing us to discard those blocks in
//! favor the the trie root. When the "ancient" blocks need to be accessed, we simply //! favor of the trie root. When the "ancient" blocks need to be accessed, we simply
//! request an inclusion proof of a specific block number against the trie with the //! request an inclusion proof of a specific block number against the trie with the
//! root has. A correct proof implies that the claimed block is identical to the one //! root has. A correct proof implies that the claimed block is identical to the one
//! we discarded. //! we discarded.

View File

@ -39,6 +39,9 @@ use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp, UntrustedRlp};
use util::{H256, U256, HeapSizeOf, RwLock}; use util::{H256, U256, HeapSizeOf, RwLock};
use util::kvdb::{DBTransaction, KeyValueDB}; use util::kvdb::{DBTransaction, KeyValueDB};
use cache::Cache;
use util::Mutex;
use smallvec::SmallVec; use smallvec::SmallVec;
/// Store at least this many candidate headers at all times. /// Store at least this many candidate headers at all times.
@ -138,11 +141,12 @@ pub struct HeaderChain {
best_block: RwLock<BlockDescriptor>, best_block: RwLock<BlockDescriptor>,
db: Arc<KeyValueDB>, db: Arc<KeyValueDB>,
col: Option<u32>, col: Option<u32>,
cache: Arc<Mutex<Cache>>,
} }
impl HeaderChain { impl HeaderChain {
/// Create a new header chain given this genesis block and database to read from. /// Create a new header chain given this genesis block and database to read from.
pub fn new(db: Arc<KeyValueDB>, col: Option<u32>, genesis: &[u8]) -> Result<Self, String> { pub fn new(db: Arc<KeyValueDB>, col: Option<u32>, genesis: &[u8], cache: Arc<Mutex<Cache>>) -> Result<Self, String> {
use ethcore::views::HeaderView; use ethcore::views::HeaderView;
let chain = if let Some(current) = db.get(col, CURRENT_KEY)? { let chain = if let Some(current) = db.get(col, CURRENT_KEY)? {
@ -186,6 +190,7 @@ impl HeaderChain {
candidates: RwLock::new(candidates), candidates: RwLock::new(candidates),
db: db, db: db,
col: col, col: col,
cache: cache,
} }
} else { } else {
let g_view = HeaderView::new(genesis); let g_view = HeaderView::new(genesis);
@ -199,6 +204,7 @@ impl HeaderChain {
candidates: RwLock::new(BTreeMap::new()), candidates: RwLock::new(BTreeMap::new()),
db: db, db: db,
col: col, col: col,
cache: cache,
} }
}; };
@ -375,11 +381,24 @@ impl HeaderChain {
/// will be returned. /// will be returned.
pub fn block_header(&self, id: BlockId) -> Option<encoded::Header> { pub fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
let load_from_db = |hash: H256| { let load_from_db = |hash: H256| {
match self.db.get(self.col, &hash) { let mut cache = self.cache.lock();
Ok(val) => val.map(|x| x.to_vec()).map(encoded::Header::new),
Err(e) => { match cache.block_header(&hash) {
warn!(target: "chain", "Failed to read from database: {}", e); Some(header) => Some(header),
None None => {
match self.db.get(self.col, &hash) {
Ok(db_value) => {
db_value.map(|x| x.to_vec()).map(encoded::Header::new)
.and_then(|header| {
cache.insert_block_header(hash.clone(), header.clone());
Some(header)
})
},
Err(e) => {
warn!(target: "chain", "Failed to read from database: {}", e);
None
}
}
} }
} }
}; };
@ -531,6 +550,10 @@ mod tests {
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use ethcore::header::Header; use ethcore::header::Header;
use ethcore::spec::Spec; use ethcore::spec::Spec;
use cache::Cache;
use time::Duration;
use util::Mutex;
fn make_db() -> Arc<::util::KeyValueDB> { fn make_db() -> Arc<::util::KeyValueDB> {
Arc::new(::util::kvdb::in_memory(0)) Arc::new(::util::kvdb::in_memory(0))
@ -542,7 +565,9 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let db = make_db(); let db = make_db();
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header)).unwrap(); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
@ -572,9 +597,10 @@ mod tests {
fn reorganize() { fn reorganize() {
let spec = Spec::new_test(); let spec = Spec::new_test();
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let db = make_db(); let db = make_db();
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header)).unwrap(); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
@ -655,8 +681,10 @@ mod tests {
let spec = Spec::new_test(); let spec = Spec::new_test();
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let db = make_db(); let db = make_db();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache).unwrap();
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header)).unwrap();
assert!(chain.block_header(BlockId::Earliest).is_some()); assert!(chain.block_header(BlockId::Earliest).is_some());
assert!(chain.block_header(BlockId::Latest).is_some()); assert!(chain.block_header(BlockId::Latest).is_some());
@ -668,9 +696,10 @@ mod tests {
let spec = Spec::new_test(); let spec = Spec::new_test();
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let db = make_db(); let db = make_db();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
{ {
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header)).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
for i in 1..10000 { for i in 1..10000 {
@ -690,7 +719,7 @@ mod tests {
} }
} }
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header)).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
assert!(chain.block_header(BlockId::Number(10)).is_none()); assert!(chain.block_header(BlockId::Number(10)).is_none());
assert!(chain.block_header(BlockId::Number(9000)).is_some()); assert!(chain.block_header(BlockId::Number(9000)).is_some());
assert!(chain.cht_root(2).is_some()); assert!(chain.cht_root(2).is_some());
@ -703,9 +732,10 @@ mod tests {
let spec = Spec::new_test(); let spec = Spec::new_test();
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let db = make_db(); let db = make_db();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
{ {
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header)).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
@ -747,7 +777,7 @@ mod tests {
} }
// after restoration, non-canonical eras should still be loaded. // after restoration, non-canonical eras should still be loaded.
let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header)).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
assert_eq!(chain.block_header(BlockId::Latest).unwrap().number(), 10); assert_eq!(chain.block_header(BlockId::Latest).unwrap().number(), 10);
assert!(chain.candidates.read().get(&100).is_some()) assert!(chain.candidates.read().get(&100).is_some())
} }

View File

@ -36,6 +36,8 @@ use util::kvdb::{KeyValueDB, CompactionProfile};
use self::header_chain::{AncestryIter, HeaderChain}; use self::header_chain::{AncestryIter, HeaderChain};
use cache::Cache;
pub use self::service::Service; pub use self::service::Service;
mod header_chain; mod header_chain;
@ -133,13 +135,13 @@ pub struct Client {
impl Client { impl Client {
/// Create a new `Client`. /// Create a new `Client`.
pub fn new(config: Config, db: Arc<KeyValueDB>, chain_col: Option<u32>, spec: &Spec, io_channel: IoChannel<ClientIoMessage>) -> Result<Self, String> { pub fn new(config: Config, db: Arc<KeyValueDB>, chain_col: Option<u32>, spec: &Spec, io_channel: IoChannel<ClientIoMessage>, cache: Arc<Mutex<Cache>>) -> Result<Self, String> {
let gh = ::rlp::encode(&spec.genesis_header()); let gh = ::rlp::encode(&spec.genesis_header());
Ok(Client { Ok(Client {
queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, true), queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, true),
engine: spec.engine.clone(), engine: spec.engine.clone(),
chain: HeaderChain::new(db.clone(), chain_col, &gh)?, chain: HeaderChain::new(db.clone(), chain_col, &gh, cache)?,
report: RwLock::new(ClientReport::default()), report: RwLock::new(ClientReport::default()),
import_lock: Mutex::new(()), import_lock: Mutex::new(()),
db: db, db: db,
@ -148,10 +150,10 @@ impl Client {
/// Create a new `Client` backed purely in-memory. /// Create a new `Client` backed purely in-memory.
/// This will ignore all database options in the configuration. /// This will ignore all database options in the configuration.
pub fn in_memory(config: Config, spec: &Spec, io_channel: IoChannel<ClientIoMessage>) -> Self { pub fn in_memory(config: Config, spec: &Spec, io_channel: IoChannel<ClientIoMessage>, cache: Arc<Mutex<Cache>>) -> Self {
let db = ::util::kvdb::in_memory(0); let db = ::util::kvdb::in_memory(0);
Client::new(config, Arc::new(db), None, spec, io_channel).expect("New DB creation infallible; qed") Client::new(config, Arc::new(db), None, spec, io_channel, cache).expect("New DB creation infallible; qed")
} }
/// Import a header to the queue for additional verification. /// Import a header to the queue for additional verification.

View File

@ -27,6 +27,9 @@ use ethcore::spec::Spec;
use io::{IoContext, IoError, IoHandler, IoService}; use io::{IoContext, IoError, IoHandler, IoService};
use util::kvdb::{Database, DatabaseConfig}; use util::kvdb::{Database, DatabaseConfig};
use cache::Cache;
use util::Mutex;
use super::{Client, Config as ClientConfig}; use super::{Client, Config as ClientConfig};
/// Errors on service initialization. /// Errors on service initialization.
@ -55,7 +58,8 @@ pub struct Service {
impl Service { impl Service {
/// Start the service: initialize I/O workers and client itself. /// Start the service: initialize I/O workers and client itself.
pub fn start(config: ClientConfig, spec: &Spec, path: &Path) -> Result<Self, Error> { pub fn start(config: ClientConfig, spec: &Spec, path: &Path, cache: Arc<Mutex<Cache>>) -> Result<Self, Error> {
// initialize database. // initialize database.
let mut db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS); let mut db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS);
@ -78,6 +82,7 @@ impl Service {
db::COL_LIGHT_CHAIN, db::COL_LIGHT_CHAIN,
spec, spec,
io_service.channel(), io_service.channel(),
cache,
).map_err(Error::Database)?); ).map_err(Error::Database)?);
io_service.register_handler(Arc::new(ImportBlocks(client.clone()))).map_err(Error::Io)?; io_service.register_handler(Arc::new(ImportBlocks(client.clone()))).map_err(Error::Io)?;
Ok(Service { Ok(Service {
@ -112,11 +117,18 @@ mod tests {
use super::Service; use super::Service;
use devtools::RandomTempPath; use devtools::RandomTempPath;
use ethcore::spec::Spec; use ethcore::spec::Spec;
use std::sync::Arc;
use cache::Cache;
use time::Duration;
use util::Mutex;
#[test] #[test]
fn it_works() { fn it_works() {
let spec = Spec::new_test(); let spec = Spec::new_test();
let temp_path = RandomTempPath::new(); let temp_path = RandomTempPath::new();
Service::start(Default::default(), &spec, temp_path.as_path()).unwrap(); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
Service::start(Default::default(), &spec, temp_path.as_path(), cache).unwrap();
} }
} }

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! PIP Protocol Version 1 implementation. //! PLP Protocol Version 1 implementation.
//! //!
//! This uses a "Provider" to answer requests. //! This uses a "Provider" to answer requests.

View File

@ -14,7 +14,8 @@
"eip155Transition": "0x7fffffffffffffff", "eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff" "eip161dTransition": "0x7fffffffffffffff",
"maxCodeSize": 24576
} }
} }
}, },

View File

@ -14,7 +14,8 @@
"eip155Transition": "0x7fffffffffffffff", "eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x0", "eip160Transition": "0x0",
"eip161abcTransition": "0x0", "eip161abcTransition": "0x0",
"eip161dTransition": "0x0" "eip161dTransition": "0x0",
"maxCodeSize": 24576
} }
} }
}, },

View File

@ -61,6 +61,11 @@ pub fn consensus_view(header: &Header) -> Result<View, ::rlp::DecoderError> {
UntrustedRlp::new(view_rlp.as_slice()).as_val() UntrustedRlp::new(view_rlp.as_slice()).as_val()
} }
/// Proposal signature.
pub fn proposal_signature(header: &Header) -> Result<H520, ::rlp::DecoderError> {
UntrustedRlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val()
}
impl Message for ConsensusMessage { impl Message for ConsensusMessage {
type Round = VoteStep; type Round = VoteStep;
@ -84,34 +89,18 @@ impl ConsensusMessage {
pub fn new_proposal(header: &Header) -> Result<Self, ::rlp::DecoderError> { pub fn new_proposal(header: &Header) -> Result<Self, ::rlp::DecoderError> {
Ok(ConsensusMessage { Ok(ConsensusMessage {
signature: proposal_signature(header)?,
vote_step: VoteStep::new(header.number() as Height, consensus_view(header)?, Step::Propose), vote_step: VoteStep::new(header.number() as Height, consensus_view(header)?, Step::Propose),
signature: UntrustedRlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val()?,
block_hash: Some(header.bare_hash()), block_hash: Some(header.bare_hash()),
}) })
} }
pub fn new_commit(proposal: &ConsensusMessage, signature: H520) -> Self {
let mut vote_step = proposal.vote_step.clone();
vote_step.step = Step::Precommit;
ConsensusMessage {
vote_step: vote_step,
block_hash: proposal.block_hash,
signature: signature,
}
}
pub fn verify(&self) -> Result<Address, Error> { pub fn verify(&self) -> Result<Address, Error> {
let full_rlp = ::rlp::encode(self); let full_rlp = ::rlp::encode(self);
let block_info = Rlp::new(&full_rlp).at(1); let block_info = Rlp::new(&full_rlp).at(1);
let public_key = recover(&self.signature.into(), &block_info.as_raw().sha3())?; let public_key = recover(&self.signature.into(), &block_info.as_raw().sha3())?;
Ok(public_to_address(&public_key)) Ok(public_to_address(&public_key))
} }
pub fn precommit_hash(&self) -> H256 {
let mut vote_step = self.vote_step.clone();
vote_step.step = Step::Precommit;
message_info_rlp(&vote_step, self.block_hash).sha3()
}
} }
impl Default for VoteStep { impl Default for VoteStep {
@ -203,6 +192,10 @@ pub fn message_full_rlp(signature: &H520, vote_info: &Bytes) -> Bytes {
s.out() s.out()
} }
pub fn message_hash(vote_step: VoteStep, block_hash: H256) -> H256 {
message_info_rlp(&vote_step, Some(block_hash)).sha3()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use util::*; use util::*;
@ -294,19 +287,6 @@ mod tests {
); );
} }
#[test]
fn message_info_from_header() {
let header = Header::default();
let pro = ConsensusMessage {
signature: Default::default(),
vote_step: VoteStep::new(0, 0, Step::Propose),
block_hash: Some(header.bare_hash())
};
let pre = message_info_rlp(&VoteStep::new(0, 0, Step::Precommit), Some(header.bare_hash()));
assert_eq!(pro.precommit_hash(), pre.sha3());
}
#[test] #[test]
fn step_ordering() { fn step_ordering() {
assert!(VoteStep::new(10, 123, Step::Precommit) < VoteStep::new(11, 123, Step::Precommit)); assert!(VoteStep::new(10, 123, Step::Precommit) < VoteStep::new(11, 123, Step::Precommit));

View File

@ -97,6 +97,8 @@ pub struct Tendermint {
proposal: RwLock<Option<H256>>, proposal: RwLock<Option<H256>>,
/// Hash of the proposal parent block. /// Hash of the proposal parent block.
proposal_parent: RwLock<H256>, proposal_parent: RwLock<H256>,
/// Last block proposed by this validator.
last_proposed: RwLock<H256>,
/// Set used to determine the current validators. /// Set used to determine the current validators.
validators: Box<ValidatorSet>, validators: Box<ValidatorSet>,
} }
@ -122,6 +124,7 @@ impl Tendermint {
last_lock: AtomicUsize::new(0), last_lock: AtomicUsize::new(0),
proposal: RwLock::new(None), proposal: RwLock::new(None),
proposal_parent: Default::default(), proposal_parent: Default::default(),
last_proposed: Default::default(),
validators: new_validator_set(our_params.validators), validators: new_validator_set(our_params.validators),
}); });
let handler = TransitionHandler::new(Arc::downgrade(&engine) as Weak<Engine>, Box::new(our_params.timeouts)); let handler = TransitionHandler::new(Arc::downgrade(&engine) as Weak<Engine>, Box::new(our_params.timeouts));
@ -196,6 +199,7 @@ impl Tendermint {
self.height.store(new_height, AtomicOrdering::SeqCst); self.height.store(new_height, AtomicOrdering::SeqCst);
self.view.store(0, AtomicOrdering::SeqCst); self.view.store(0, AtomicOrdering::SeqCst);
*self.lock_change.write() = None; *self.lock_change.write() = None;
*self.proposal.write() = None;
} }
/// Use via step_service to transition steps. /// Use via step_service to transition steps.
@ -206,7 +210,6 @@ impl Tendermint {
*self.step.write() = step; *self.step.write() = step;
match step { match step {
Step::Propose => { Step::Propose => {
*self.proposal.write() = None;
self.update_sealing() self.update_sealing()
}, },
Step::Prevote => { Step::Prevote => {
@ -230,28 +233,6 @@ impl Tendermint {
}, },
Step::Commit => { Step::Commit => {
trace!(target: "engine", "to_step: Commit."); trace!(target: "engine", "to_step: Commit.");
// Commit the block using a complete signature set.
let view = self.view.load(AtomicOrdering::SeqCst);
let height = self.height.load(AtomicOrdering::SeqCst);
if let Some(block_hash) = *self.proposal.read() {
// Generate seal and remove old votes.
if self.is_signer_proposer(&*self.proposal_parent.read()) {
let proposal_step = VoteStep::new(height, view, Step::Propose);
let precommit_step = VoteStep::new(proposal_step.height, proposal_step.view, Step::Precommit);
if let Some(seal) = self.votes.seal_signatures(proposal_step, precommit_step, &block_hash) {
trace!(target: "engine", "Collected seal: {:?}", seal);
let seal = vec![
::rlp::encode(&view).to_vec(),
::rlp::encode(&seal.proposal).to_vec(),
::rlp::encode_list(&seal.votes).to_vec()
];
self.submit_seal(block_hash, seal);
self.to_next_height(height);
} else {
warn!(target: "engine", "Not enough votes found!");
}
}
}
}, },
} }
} }
@ -260,8 +241,17 @@ impl Tendermint {
self.validators.contains(&*self.proposal_parent.read(), address) self.validators.contains(&*self.proposal_parent.read(), address)
} }
fn is_above_threshold(&self, n: usize) -> bool { fn check_above_threshold(&self, n: usize) -> Result<(), EngineError> {
n > self.validators.count(&*self.proposal_parent.read()) * 2/3 let threshold = self.validators.count(&*self.proposal_parent.read()) * 2/3;
if n > threshold {
Ok(())
} else {
Err(EngineError::BadSealFieldSize(OutOfBounds {
min: Some(threshold),
max: None,
found: n
}))
}
} }
/// Find the designated for the given view. /// Find the designated for the given view.
@ -272,7 +262,7 @@ impl Tendermint {
} }
/// Check if address is a proposer for given view. /// Check if address is a proposer for given view.
fn is_view_proposer(&self, bh: &H256, height: Height, view: View, address: &Address) -> Result<(), EngineError> { fn check_view_proposer(&self, bh: &H256, height: Height, view: View, address: &Address) -> Result<(), EngineError> {
let proposer = self.view_proposer(bh, height, view); let proposer = self.view_proposer(bh, height, view);
if proposer == *address { if proposer == *address {
Ok(()) Ok(())
@ -308,13 +298,13 @@ impl Tendermint {
fn has_enough_any_votes(&self) -> bool { fn has_enough_any_votes(&self) -> bool {
let step_votes = self.votes.count_round_votes(&VoteStep::new(self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst), *self.step.read())); let step_votes = self.votes.count_round_votes(&VoteStep::new(self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst), *self.step.read()));
self.is_above_threshold(step_votes) self.check_above_threshold(step_votes).is_ok()
} }
fn has_enough_future_step_votes(&self, vote_step: &VoteStep) -> bool { fn has_enough_future_step_votes(&self, vote_step: &VoteStep) -> bool {
if vote_step.view > self.view.load(AtomicOrdering::SeqCst) { if vote_step.view > self.view.load(AtomicOrdering::SeqCst) {
let step_votes = self.votes.count_round_votes(vote_step); let step_votes = self.votes.count_round_votes(vote_step);
self.is_above_threshold(step_votes) self.check_above_threshold(step_votes).is_ok()
} else { } else {
false false
} }
@ -322,7 +312,7 @@ impl Tendermint {
fn has_enough_aligned_votes(&self, message: &ConsensusMessage) -> bool { fn has_enough_aligned_votes(&self, message: &ConsensusMessage) -> bool {
let aligned_count = self.votes.count_aligned_votes(&message); let aligned_count = self.votes.count_aligned_votes(&message);
self.is_above_threshold(aligned_count) self.check_above_threshold(aligned_count).is_ok()
} }
fn handle_valid_message(&self, message: &ConsensusMessage) { fn handle_valid_message(&self, message: &ConsensusMessage) {
@ -337,18 +327,32 @@ impl Tendermint {
&& self.has_enough_aligned_votes(message); && self.has_enough_aligned_votes(message);
if lock_change { if lock_change {
trace!(target: "engine", "handle_valid_message: Lock change."); trace!(target: "engine", "handle_valid_message: Lock change.");
*self.lock_change.write() = Some(message.clone()); *self.lock_change.write() = Some(message.clone());
} }
// Check if it can affect the step transition. // Check if it can affect the step transition.
if self.is_height(message) { if self.is_height(message) {
let next_step = match *self.step.read() { let next_step = match *self.step.read() {
Step::Precommit if message.block_hash.is_none() && self.has_enough_aligned_votes(message) => {
self.increment_view(1);
Some(Step::Propose)
},
Step::Precommit if self.has_enough_aligned_votes(message) => { Step::Precommit if self.has_enough_aligned_votes(message) => {
if message.block_hash.is_none() { let bh = message.block_hash.expect("previous guard ensures is_some; qed");
self.increment_view(1); if *self.last_proposed.read() == bh {
Some(Step::Propose) // Commit the block using a complete signature set.
} else { // Generate seal and remove old votes.
Some(Step::Commit) let precommits = self.votes.round_signatures(vote_step, &bh);
trace!(target: "engine", "Collected seal: {:?}", precommits);
let seal = vec![
::rlp::encode(&vote_step.view).to_vec(),
::rlp::NULL_RLP.to_vec(),
::rlp::encode_list(&precommits).to_vec()
];
self.submit_seal(bh, seal);
self.votes.throw_out_old(&vote_step);
} }
self.to_next_height(self.height.load(AtomicOrdering::SeqCst));
Some(Step::Commit)
}, },
Step::Precommit if self.has_enough_future_step_votes(&vote_step) => { Step::Precommit if self.has_enough_future_step_votes(&vote_step) => {
self.increment_view(vote_step.view - self.view.load(AtomicOrdering::SeqCst)); self.increment_view(vote_step.view - self.view.load(AtomicOrdering::SeqCst));
@ -442,6 +446,8 @@ impl Engine for Tendermint {
// Insert Propose vote. // Insert Propose vote.
debug!(target: "engine", "Submitting proposal {} at height {} view {}.", header.bare_hash(), height, view); debug!(target: "engine", "Submitting proposal {} at height {} view {}.", header.bare_hash(), height, view);
self.votes.vote(ConsensusMessage::new(signature, height, view, Step::Propose, bh), author); self.votes.vote(ConsensusMessage::new(signature, height, view, Step::Propose, bh), author);
// Remember the owned block.
*self.last_proposed.write() = header.bare_hash();
// Remember proposal for later seal submission. // Remember proposal for later seal submission.
*self.proposal.write() = bh; *self.proposal.write() = bh;
*self.proposal_parent.write() = header.parent_hash().clone(); *self.proposal_parent.write() = header.parent_hash().clone();
@ -462,12 +468,12 @@ impl Engine for Tendermint {
if !self.votes.is_old_or_known(&message) { if !self.votes.is_old_or_known(&message) {
let sender = public_to_address(&recover(&message.signature.into(), &rlp.at(1)?.as_raw().sha3())?); let sender = public_to_address(&recover(&message.signature.into(), &rlp.at(1)?.as_raw().sha3())?);
if !self.is_authority(&sender) { if !self.is_authority(&sender) {
Err(EngineError::NotAuthorized(sender))?; return Err(EngineError::NotAuthorized(sender).into());
} }
self.broadcast_message(rlp.as_raw().to_vec()); self.broadcast_message(rlp.as_raw().to_vec());
if self.votes.vote(message.clone(), &sender).is_some() { if self.votes.vote(message.clone(), &sender).is_some() {
self.validators.report_malicious(&sender); self.validators.report_malicious(&sender);
Err(EngineError::DoubleVote(sender))? return Err(EngineError::DoubleVote(sender).into());
} }
trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender); trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender);
self.handle_valid_message(&message); self.handle_valid_message(&message);
@ -491,22 +497,19 @@ impl Engine for Tendermint {
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
let seal_length = header.seal().len(); let seal_length = header.seal().len();
if seal_length == self.seal_fields() { if seal_length == self.seal_fields() {
let signatures_len = header.seal()[2].len(); // Either proposal or commit.
if signatures_len >= 1 { if (header.seal()[1] == ::rlp::NULL_RLP.to_vec())
!= (header.seal()[2] == ::rlp::EMPTY_LIST_RLP.to_vec()) {
Ok(()) Ok(())
} else { } else {
Err(From::from(EngineError::BadSealFieldSize(OutOfBounds { warn!(target: "engine", "verify_block_basic: Block is neither a Commit nor Proposal.");
min: Some(1), Err(BlockError::InvalidSeal.into())
max: None,
found: signatures_len
})))
} }
} else { } else {
Err(From::from(BlockError::InvalidSealArity( Err(BlockError::InvalidSealArity(
Mismatch { expected: self.seal_fields(), found: seal_length } Mismatch { expected: self.seal_fields(), found: seal_length }
))) ).into())
} }
} }
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
@ -515,50 +518,42 @@ impl Engine for Tendermint {
/// Verify validators and gas limit. /// Verify validators and gas limit.
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
let proposal = ConsensusMessage::new_proposal(header)?;
let proposer = proposal.verify()?;
if !self.is_authority(&proposer) {
Err(EngineError::NotAuthorized(proposer))?
}
let precommit_hash = proposal.precommit_hash();
let ref signatures_field = header.seal()[2];
let mut signature_count = 0;
let mut origins = HashSet::new();
for rlp in UntrustedRlp::new(signatures_field).iter() {
let precommit: ConsensusMessage = ConsensusMessage::new_commit(&proposal, rlp.as_val()?);
let address = match self.votes.get(&precommit) {
Some(a) => a,
None => public_to_address(&recover(&precommit.signature.into(), &precommit_hash)?),
};
if !self.validators.contains(header.parent_hash(), &address) {
Err(EngineError::NotAuthorized(address.to_owned()))?
}
if origins.insert(address) {
signature_count += 1;
} else {
warn!(target: "engine", "verify_block_unordered: Duplicate signature from {} on the seal.", address);
Err(BlockError::InvalidSeal)?;
}
}
// Check if its a proposal if there is not enough precommits.
if !self.is_above_threshold(signature_count) {
let signatures_len = signatures_field.len();
// Proposal has to have an empty signature list.
if signatures_len != 1 {
Err(EngineError::BadSealFieldSize(OutOfBounds {
min: Some(1),
max: Some(1),
found: signatures_len
}))?;
}
self.is_view_proposer(header.parent_hash(), proposal.vote_step.height, proposal.vote_step.view, &proposer)?;
}
if header.number() == 0 { if header.number() == 0 {
Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))?; return Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }).into());
}
if let Ok(proposal) = ConsensusMessage::new_proposal(header) {
let proposer = proposal.verify()?;
if !self.is_authority(&proposer) {
return Err(EngineError::NotAuthorized(proposer).into());
}
self.check_view_proposer(header.parent_hash(), proposal.vote_step.height, proposal.vote_step.view, &proposer)?;
} else {
let vote_step = VoteStep::new(header.number() as usize, consensus_view(header)?, Step::Precommit);
let precommit_hash = message_hash(vote_step.clone(), header.bare_hash());
let ref signatures_field = header.seal().get(2).expect("block went through verify_block_basic; block has .seal_fields() fields; qed");
let mut origins = HashSet::new();
for rlp in UntrustedRlp::new(signatures_field).iter() {
let precommit = ConsensusMessage {
signature: rlp.as_val()?,
block_hash: Some(header.bare_hash()),
vote_step: vote_step.clone(),
};
let address = match self.votes.get(&precommit) {
Some(a) => a,
None => public_to_address(&recover(&precommit.signature.into(), &precommit_hash)?),
};
if !self.validators.contains(header.parent_hash(), &address) {
return Err(EngineError::NotAuthorized(address.to_owned()).into());
}
if !origins.insert(address) {
warn!(target: "engine", "verify_block_unordered: Duplicate signature from {} on the seal.", address);
return Err(BlockError::InvalidSeal.into());
}
}
self.check_above_threshold(origins.len())?
} }
let gas_limit_divisor = self.gas_limit_bound_divisor; let gas_limit_divisor = self.gas_limit_bound_divisor;
@ -566,7 +561,7 @@ impl Engine for Tendermint {
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor; let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas { if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
self.validators.report_malicious(header.author()); self.validators.report_malicious(header.author());
Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }))?; return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
} }
Ok(()) Ok(())
@ -590,13 +585,14 @@ impl Engine for Tendermint {
fn is_proposal(&self, header: &Header) -> bool { fn is_proposal(&self, header: &Header) -> bool {
let signatures_len = header.seal()[2].len(); let signatures_len = header.seal()[2].len();
// Signatures have to be an empty list rlp. // Signatures have to be an empty list rlp.
let proposal = ConsensusMessage::new_proposal(header).expect("block went through full verification; this Engine verifies new_proposal creation; qed");
if signatures_len != 1 { if signatures_len != 1 {
// New Commit received, skip to next height. // New Commit received, skip to next height.
trace!(target: "engine", "Received a commit: {:?}.", proposal.vote_step); trace!(target: "engine", "Received a commit: {:?}.", header.number());
self.to_next_height(proposal.vote_step.height); self.to_next_height(header.number() as usize);
self.to_step(Step::Commit);
return false; return false;
} }
let proposal = ConsensusMessage::new_proposal(header).expect("block went through full verification; this Engine verifies new_proposal creation; qed");
let proposer = proposal.verify().expect("block went through full verification; this Engine tries verify; qed"); let proposer = proposal.verify().expect("block went through full verification; this Engine tries verify; qed");
debug!(target: "engine", "Received a new proposal {:?} from {}.", proposal.vote_step, proposer); debug!(target: "engine", "Received a new proposal {:?} from {}.", proposal.vote_step, proposer);
if self.is_view(&proposal) { if self.is_view(&proposal) {
@ -647,6 +643,10 @@ impl Engine for Tendermint {
} }
fn register_client(&self, client: Weak<Client>) { fn register_client(&self, client: Weak<Client>) {
use client::BlockChainClient;
if let Some(c) = client.upgrade() {
self.height.store(c.chain_info().best_block_number as usize + 1, AtomicOrdering::SeqCst);
}
*self.client.write() = Some(client.clone()); *self.client.write() = Some(client.clone());
self.validators.register_contract(client); self.validators.register_contract(client);
} }
@ -825,6 +825,7 @@ mod tests {
let vote_info = message_info_rlp(&VoteStep::new(2, 0, Step::Precommit), Some(header.bare_hash())); let vote_info = message_info_rlp(&VoteStep::new(2, 0, Step::Precommit), Some(header.bare_hash()));
let signature1 = tap.sign(proposer, None, vote_info.sha3()).unwrap(); let signature1 = tap.sign(proposer, None, vote_info.sha3()).unwrap();
seal[1] = ::rlp::NULL_RLP.to_vec();
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone())]).to_vec(); seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone())]).to_vec();
header.set_seal(seal.clone()); header.set_seal(seal.clone());

View File

@ -136,30 +136,14 @@ impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
*guard = new_collector; *guard = new_collector;
} }
/// Collects the signatures used to seal a block. /// Collects the signatures for a given round and hash.
pub fn seal_signatures(&self, proposal_round: M::Round, commit_round: M::Round, block_hash: &H256) -> Option<SealSignatures> { pub fn round_signatures(&self, round: &M::Round, block_hash: &H256) -> Vec<H520> {
let ref bh = Some(*block_hash); let guard = self.votes.read();
let maybe_seal = { guard
let guard = self.votes.read(); .get(round)
guard .and_then(|c| c.block_votes.get(&Some(*block_hash)))
.get(&proposal_round) .map(|votes| votes.keys().cloned().collect())
.and_then(|c| c.block_votes.get(bh)) .unwrap_or_else(Vec::new)
.and_then(|proposals| proposals.keys().next())
.map(|proposal| SealSignatures {
proposal: proposal.clone(),
votes: guard
.get(&commit_round)
.and_then(|c| c.block_votes.get(bh))
.map(|precommits| precommits.keys().cloned().collect())
.unwrap_or_else(Vec::new),
})
.and_then(|seal| if seal.votes.is_empty() { None } else { Some(seal) })
};
if maybe_seal.is_some() {
// Remove messages that are no longer relevant.
self.throw_out_old(&commit_round);
}
maybe_seal
} }
/// Count votes which agree with the given message. /// Count votes which agree with the given message.
@ -275,11 +259,9 @@ mod tests {
random_vote(&collector, signatures[1].clone(), commit_round.clone(), bh.clone()); random_vote(&collector, signatures[1].clone(), commit_round.clone(), bh.clone());
// Wrong round, same signature. // Wrong round, same signature.
random_vote(&collector, signatures[1].clone(), 7, bh.clone()); random_vote(&collector, signatures[1].clone(), 7, bh.clone());
let seal = SealSignatures {
proposal: signatures[0], assert_eq!(signatures[0..1].to_vec(), collector.round_signatures(&propose_round, &bh.unwrap()));
votes: signatures[1..3].to_vec() assert_eq!(signatures[1..3].iter().collect::<HashSet<_>>(), collector.round_signatures(&commit_round, &bh.unwrap()).iter().collect::<HashSet<_>>());
};
assert_eq!(seal, collector.seal_signatures(propose_round, commit_round, &bh.unwrap()).unwrap());
} }
#[test] #[test]

View File

@ -48,7 +48,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Frontier => ethereum::new_frontier_test(),
ChainEra::Homestead => ethereum::new_homestead_test(), ChainEra::Homestead => ethereum::new_homestead_test(),
ChainEra::Eip150 => ethereum::new_eip150_test(), ChainEra::Eip150 => ethereum::new_eip150_test(),
ChainEra::Eip161 => ethereum::new_eip161_test(), ChainEra::_Eip161 => ethereum::new_eip161_test(),
ChainEra::TransitionTest => ethereum::new_transition_test(), ChainEra::TransitionTest => ethereum::new_transition_test(),
}; };
spec.set_genesis_state(state); spec.set_genesis_state(state);

View File

@ -1,43 +0,0 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use super::test_common::*;
use tests::helpers::*;
use super::state::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip150)
}
declare_test!{StateTests_EIP150_stEIPSpecificTest, "StateTests/EIP150/stEIPSpecificTest"}
declare_test!{StateTests_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP150/stEIPsingleCodeGasPrices"}
declare_test!{StateTests_EIP150_stMemExpandingEIPCalls, "StateTests/EIP150/stMemExpandingEIPCalls"}
declare_test!{StateTests_EIP150_stCallCodes, "StateTests/EIP150/Homestead/stCallCodes"}
declare_test!{StateTests_EIP150_stCallCreateCallCodeTest, "StateTests/EIP150/Homestead/stCallCreateCallCodeTest"}
declare_test!{StateTests_EIP150_stDelegatecallTest, "StateTests/EIP150/Homestead/stDelegatecallTest"}
declare_test!{StateTests_EIP150_stInitCodeTest, "StateTests/EIP150/Homestead/stInitCodeTest"}
declare_test!{StateTests_EIP150_stLogTests, "StateTests/EIP150/Homestead/stLogTests"}
declare_test!{heavy => StateTests_EIP150_stMemoryStressTest, "StateTests/EIP150/Homestead/stMemoryStressTest"}
declare_test!{heavy => StateTests_EIP150_stMemoryTest, "StateTests/EIP150/Homestead/stMemoryTest"}
declare_test!{StateTests_EIP150_stPreCompiledContracts, "StateTests/EIP150/Homestead/stPreCompiledContracts"}
declare_test!{heavy => StateTests_EIP150_stQuadraticComplexityTest, "StateTests/EIP150/Homestead/stQuadraticComplexityTest"}
declare_test!{StateTests_EIP150_stRecursiveCreate, "StateTests/EIP150/Homestead/stRecursiveCreate"}
declare_test!{StateTests_EIP150_stRefundTest, "StateTests/EIP150/Homestead/stRefundTest"}
declare_test!{StateTests_EIP150_stSpecialTest, "StateTests/EIP150/Homestead/stSpecialTest"}
declare_test!{StateTests_EIP150_stSystemOperationsTest, "StateTests/EIP150/Homestead/stSystemOperationsTest"}
declare_test!{StateTests_EIP150_stTransactionTest, "StateTests/EIP150/Homestead/stTransactionTest"}
declare_test!{StateTests_EIP150_stWalletTest, "StateTests/EIP150/Homestead/stWalletTest"}

View File

@ -1,51 +0,0 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use super::test_common::*;
use tests::helpers::*;
use super::state::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip161)
}
declare_test!{StateTests_EIP158_stEIP158SpecificTest, "StateTests/EIP158/stEIP158SpecificTest"}
declare_test!{StateTests_EIP158_stNonZeroCallsTest, "StateTests/EIP158/stNonZeroCallsTest"}
declare_test!{StateTests_EIP158_stZeroCallsTest, "StateTests/EIP158/stZeroCallsTest"}
declare_test!{StateTests_EIP158_EIP150_stMemExpandingEIPCalls, "StateTests/EIP158/EIP150/stMemExpandingEIPCalls"}
declare_test!{StateTests_EIP158_EIP150_stEIPSpecificTest, "StateTests/EIP158/EIP150/stEIPSpecificTest"}
declare_test!{StateTests_EIP158_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP158/EIP150/stEIPsingleCodeGasPrices"}
declare_test!{StateTests_EIP158_EIP150_stChangedTests, "StateTests/EIP158/EIP150/stChangedTests"}
declare_test!{StateTests_EIP158_Homestead_stBoundsTest, "StateTests/EIP158/Homestead/stBoundsTest"}
declare_test!{StateTests_EIP158_Homestead_stCallCodes, "StateTests/EIP158/Homestead/stCallCodes"}
declare_test!{StateTests_EIP158_Homestead_stCallCreateCallCodeTest, "StateTests/EIP158/Homestead/stCallCreateCallCodeTest"}
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodes, "StateTests/EIP158/Homestead/stCallDelegateCodes"}
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodesCallCode, "StateTests/EIP158/Homestead/stCallDelegateCodesCallCode"}
declare_test!{StateTests_EIP158_Homestead_stDelegatecallTest, "StateTests/EIP158/Homestead/stDelegatecallTest"}
declare_test!{StateTests_EIP158_Homestead_stHomeSteadSpecific, "StateTests/EIP158/Homestead/stHomeSteadSpecific"}
declare_test!{StateTests_EIP158_Homestead_stInitCodeTest, "StateTests/EIP158/Homestead/stInitCodeTest"}
declare_test!{StateTests_EIP158_Homestead_stLogTests, "StateTests/EIP158/Homestead/stLogTests"}
declare_test!{heavy => StateTests_EIP158_Homestead_stMemoryTest, "StateTests/EIP158/Homestead/stMemoryTest"}
declare_test!{StateTests_EIP158_Homestead_stPreCompiledContracts, "StateTests/EIP158/Homestead/stPreCompiledContracts"}
declare_test!{heavy => StateTests_EIP158_Homestead_stQuadraticComplexityTest, "StateTests/EIP158/Homestead/stQuadraticComplexityTest"}
declare_test!{StateTests_EIP158_Homestead_stRecursiveCreate, "StateTests/EIP158/Homestead/stRecursiveCreate"}
declare_test!{StateTests_EIP158_Homestead_stRefundTest, "StateTests/EIP158/Homestead/stRefundTest"}
declare_test!{StateTests_EIP158_Homestead_stSpecialTest, "StateTests/EIP158/Homestead/stSpecialTest"}
declare_test!{StateTests_EIP158_Homestead_stSystemOperationsTest, "StateTests/EIP158/Homestead/stSystemOperationsTest"}
declare_test!{StateTests_EIP158_Homestead_stTransactionTest, "StateTests/EIP158/Homestead/stTransactionTest"}
declare_test!{StateTests_EIP158_Homestead_stWalletTest, "StateTests/EIP158/Homestead/stWalletTest"}

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use super::test_common::*;
use super::chain::json_chain_test; use super::chain::json_chain_test;
use tests::helpers::*; use tests::helpers::*;

View File

@ -1,39 +0,0 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use super::test_common::*;
use tests::helpers::*;
use super::state::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Homestead)
}
declare_test!{StateTests_Homestead_stCallCodes, "StateTests/Homestead/stCallCodes"}
declare_test!{StateTests_Homestead_stCallCreateCallCodeTest, "StateTests/Homestead/stCallCreateCallCodeTest"}
declare_test!{StateTests_Homestead_stDelegatecallTest, "StateTests/Homestead/stDelegatecallTest"}
declare_test!{StateTests_Homestead_stInitCodeTest, "StateTests/Homestead/stInitCodeTest"}
declare_test!{StateTests_Homestead_stLogTests, "StateTests/Homestead/stLogTests"}
declare_test!{heavy => StateTests_Homestead_stMemoryStressTest, "StateTests/Homestead/stMemoryStressTest"}
declare_test!{heavy => StateTests_Homestead_stMemoryTest, "StateTests/Homestead/stMemoryTest"}
declare_test!{StateTests_Homestead_stPreCompiledContracts, "StateTests/Homestead/stPreCompiledContracts"}
declare_test!{heavy => StateTests_Homestead_stQuadraticComplexityTest, "StateTests/Homestead/stQuadraticComplexityTest"}
declare_test!{StateTests_Homestead_stRecursiveCreate, "StateTests/Homestead/stRecursiveCreate"}
declare_test!{StateTests_Homestead_stRefundTest, "StateTests/Homestead/stRefundTest"}
declare_test!{StateTests_Homestead_stSpecialTest, "StateTests/Homestead/stSpecialTest"}
declare_test!{StateTests_Homestead_stSystemOperationsTest, "StateTests/Homestead/stSystemOperationsTest"}
declare_test!{StateTests_Homestead_stTransactionTest, "StateTests/Homestead/stTransactionTest"}
declare_test!{StateTests_Homestead_stWalletTest, "StateTests/Homestead/stWalletTest"}

View File

@ -21,8 +21,5 @@ mod transaction;
mod executive; mod executive;
mod state; mod state;
mod chain; mod chain;
mod homestead_state;
mod homestead_chain; mod homestead_chain;
mod eip150_state;
mod eip161_state;
mod trie; mod trie;

View File

@ -16,749 +16,109 @@
use super::test_common::*; use super::test_common::*;
use tests::helpers::*; use tests::helpers::*;
use pod_state::{self, PodState}; use pod_state::PodState;
use log_entry::LogEntry;
use ethereum; use ethereum;
use spec::Spec;
use ethjson; use ethjson;
use ethjson::state::test::ForkSpec;
pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> { lazy_static! {
pub static ref FRONTIER: Spec = ethereum::new_frontier_test();
pub static ref HOMESTEAD: Spec = ethereum::new_homestead_test();
pub static ref EIP150: Spec = ethereum::new_eip150_test();
pub static ref EIP161: Spec = ethereum::new_eip161_test();
}
pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {
::ethcore_logger::init_log(); ::ethcore_logger::init_log();
let tests = ethjson::state::Test::load(json_data).unwrap(); let tests = ethjson::state::test::Test::load(json_data).unwrap();
let mut failed = Vec::new(); let mut failed = Vec::new();
let engine = match era {
ChainEra::Frontier => ethereum::new_mainnet_like().engine,
ChainEra::Homestead => ethereum::new_homestead_test().engine,
ChainEra::Eip150 => ethereum::new_eip150_test().engine,
ChainEra::Eip161 => ethereum::new_eip161_test().engine,
ChainEra::TransitionTest => ethereum::new_transition_test().engine,
};
for (name, test) in tests.into_iter() { for (name, test) in tests.into_iter() {
let mut fail = false;
{ {
let mut fail_unless = |cond: bool| if !cond && !fail { let multitransaction = test.transaction;
failed.push(name.clone());
flushln!("FAIL");
fail = true;
true
} else {false};
flush!(" - {}...", name);
let transaction = test.transaction.into();
let post_state_root = test.post_state_root.into();
let env = test.env.into(); let env = test.env.into();
let pre: PodState = test.pre_state.into(); let pre: PodState = test.pre_state.into();
let post: PodState = test.post_state.into();
let logs: Vec<LogEntry> = test.logs.into_iter().map(Into::into).collect();
let calc_post = sec_trie_root(post.get().iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect()); for (spec, states) in test.post_states {
let total = states.len();
let engine = match spec {
ForkSpec::Frontier => &FRONTIER.engine,
ForkSpec::Homestead => &HOMESTEAD.engine,
ForkSpec::EIP150 => &EIP150.engine,
ForkSpec::EIP158 => &EIP161.engine,
ForkSpec::Metropolis => continue,
};
if fail_unless(post_state_root == calc_post) { for (i, state) in states.into_iter().enumerate() {
println!("!!! {}: Trie root mismatch (got: {}, expect: {}):", name, calc_post, post_state_root); let info = format!(" - {} | {:?} ({}/{}) ...", name, spec, i + 1, total);
println!("!!! Post:\n{}", post);
} else {
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.populate_from(pre);
state.commit()
.expect(&format!("State test {} failed due to internal error.", name));
let res = state.apply(&env, &*engine, &transaction, false);
if fail_unless(state.root() == &post_state_root) { let post_root: H256 = state.hash.into();
println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root); let transaction = multitransaction.select(&state.indexes).into();
let our_post = state.to_pod();
println!("Got:\n{}", our_post);
println!("Expect:\n{}", post);
println!("Diff ---expect -> +++got:\n{}", pod_state::diff_pod(&post, &our_post));
}
if let Ok(r) = res { let mut state = get_temp_mem_state();
if fail_unless(logs == r.receipt.logs) { state.populate_from(pre.clone());
println!("!!! {}: Logs mismatch:", name); state.commit().expect(&format!("State test {} failed due to internal error.", name));
println!("Got:\n{:?}", r.receipt.logs); let _res = state.apply(&env, &**engine, &transaction, false);
println!("Expect:\n{:?}", logs); if state.root() != &post_root {
println!("{} !!! State mismatch (got: {}, expect: {}", info, state.root(), post_root);
flushln!("{} fail", info);
failed.push(name.clone());
} else {
flushln!("{} ok", info);
} }
} }
} }
} }
if !fail {
flushln!("ok");
}
} }
println!("!!! {:?} tests from failed.", failed.len()); println!("!!! {:?} tests from failed.", failed.len());
failed failed
} }
mod frontier_tests { mod state_tests {
use super::json_chain_test; use super::json_chain_test;
use tests::helpers::ChainEra;
fn do_json_test(json_data: &[u8]) -> Vec<String> { fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Frontier) json_chain_test(json_data)
} }
declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"} declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"}
declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"} declare_test!{GeneralStateTest_stBlockHashTest, "GeneralStateTests/stBlockHashTest/"}
declare_test!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} declare_test!{GeneralStateTest_stBoundsTest, "GeneralStateTests/stBoundsTest/"}
declare_test!{StateTests_stExample, "StateTests/stExample"} declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"}
declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"} declare_test!{skip => [ "createJS_ExampleContract" ], GeneralStateTest_stCallCreateCallCodeTest, "GeneralStateTests/stCallCreateCallCodeTest/"}
declare_test!{StateTests_stLogTests, "StateTests/stLogTests"} declare_test!{GeneralStateTest_stCallDelegateCodesCallCodeHomestead, "GeneralStateTests/stCallDelegateCodesCallCodeHomestead/"}
declare_test!{heavy => StateTests_stMemoryStressTest, "StateTests/stMemoryStressTest"} declare_test!{GeneralStateTest_stCallDelegateCodesHomestead, "GeneralStateTests/stCallDelegateCodesHomestead/"}
declare_test!{heavy => StateTests_stMemoryTest, "StateTests/stMemoryTest"} declare_test!{GeneralStateTest_stChangedEIP150, "GeneralStateTests/stChangedEIP150/"}
declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"} declare_test!{GeneralStateTest_stCodeSizeLimit, "GeneralStateTests/stCodeSizeLimit/"}
declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} declare_test!{GeneralStateTest_stCreateTest, "GeneralStateTests/stCreateTest/"}
declare_test!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} declare_test!{GeneralStateTest_stDelegatecallTestHomestead, "GeneralStateTests/stDelegatecallTestHomestead/"}
declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"} declare_test!{GeneralStateTest_stEIP150singleCodeGasPrices, "GeneralStateTests/stEIP150singleCodeGasPrices/"}
declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} declare_test!{GeneralStateTest_stEIP150Specific, "GeneralStateTests/stEIP150Specific/"}
declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} declare_test!{GeneralStateTest_stExample, "GeneralStateTests/stExample/"}
declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{GeneralStateTest_stHomesteadSpecific, "GeneralStateTests/stHomesteadSpecific/"}
declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} declare_test!{GeneralStateTest_stInitCodeTest, "GeneralStateTests/stInitCodeTest/"}
declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{GeneralStateTest_stLogTests, "GeneralStateTests/stLogTests/"}
declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} declare_test!{GeneralStateTest_stMemExpandingEIP150Calls, "GeneralStateTests/stMemExpandingEIP150Calls/"}
declare_test!{heavy => GeneralStateTest_stMemoryStressTest, "GeneralStateTests/stMemoryStressTest/"}
declare_test!{StateTests_RandomTests_st201503121803PYTHON, "StateTests/RandomTests/st201503121803PYTHON"} declare_test!{GeneralStateTest_stMemoryTest, "GeneralStateTests/stMemoryTest/"}
declare_test!{StateTests_RandomTests_st201503121806PYTHON, "StateTests/RandomTests/st201503121806PYTHON"} declare_test!{GeneralStateTest_stNonZeroCallsTest, "GeneralStateTests/stNonZeroCallsTest/"}
declare_test!{StateTests_RandomTests_st201503121848GO, "StateTests/RandomTests/st201503121848GO"} declare_test!{GeneralStateTest_stPreCompiledContracts, "GeneralStateTests/stPreCompiledContracts/"}
declare_test!{StateTests_RandomTests_st201503121849GO, "StateTests/RandomTests/st201503121849GO"} declare_test!{heavy => GeneralStateTest_stQuadraticComplexityTest, "GeneralStateTests/stQuadraticComplexityTest/"}
declare_test!{StateTests_RandomTests_st201503121850GO, "StateTests/RandomTests/st201503121850GO"} declare_test!{GeneralStateTest_stRandom, "GeneralStateTests/stRandom/"}
declare_test!{StateTests_RandomTests_st201503121851GO, "StateTests/RandomTests/st201503121851GO"} declare_test!{GeneralStateTest_stRecursiveCreate, "GeneralStateTests/stRecursiveCreate/"}
declare_test!{StateTests_RandomTests_st201503121953GO, "StateTests/RandomTests/st201503121953GO"} declare_test!{GeneralStateTest_stRefundTest, "GeneralStateTests/stRefundTest/"}
declare_test!{StateTests_RandomTests_st201503122023GO, "StateTests/RandomTests/st201503122023GO"} declare_test!{skip => [ "RevertDepthCreateAddressCollision" ], GeneralStateTest_stRevertTest, "GeneralStateTests/stRevertTest/"}
declare_test!{StateTests_RandomTests_st201503122023PYTHON, "StateTests/RandomTests/st201503122023PYTHON"} declare_test!{GeneralStateTest_stSolidityTest, "GeneralStateTests/stSolidityTest/"}
declare_test!{StateTests_RandomTests_st201503122027GO, "StateTests/RandomTests/st201503122027GO"} declare_test!{GeneralStateTest_stSpecialTest, "GeneralStateTests/stSpecialTest/"}
declare_test!{StateTests_RandomTests_st201503122054GO, "StateTests/RandomTests/st201503122054GO"} declare_test!{GeneralStateTest_stStackTests, "GeneralStateTests/stStackTests/"}
declare_test!{StateTests_RandomTests_st201503122055GO, "StateTests/RandomTests/st201503122055GO"} declare_test!{GeneralStateTest_stSystemOperationsTest, "GeneralStateTests/stSystemOperationsTest/"}
declare_test!{StateTests_RandomTests_st201503122115CPPJIT, "StateTests/RandomTests/st201503122115CPPJIT"} declare_test!{GeneralStateTest_stTransactionTest, "GeneralStateTests/stTransactionTest/"}
declare_test!{StateTests_RandomTests_st201503122115GO, "StateTests/RandomTests/st201503122115GO"} declare_test!{GeneralStateTest_stTransitionTest, "GeneralStateTests/stTransitionTest/"}
declare_test!{StateTests_RandomTests_st201503122123GO, "StateTests/RandomTests/st201503122123GO"} declare_test!{GeneralStateTest_stWalletTest, "GeneralStateTests/stWalletTest/"}
declare_test!{StateTests_RandomTests_st201503122124GO, "StateTests/RandomTests/st201503122124GO"} declare_test!{GeneralStateTest_stZeroCallsRevert, "GeneralStateTests/stZeroCallsRevert/"}
declare_test!{StateTests_RandomTests_st201503122128PYTHON, "StateTests/RandomTests/st201503122128PYTHON"} declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"}
declare_test!{StateTests_RandomTests_st201503122140GO, "StateTests/RandomTests/st201503122140GO"}
declare_test!{StateTests_RandomTests_st201503122159GO, "StateTests/RandomTests/st201503122159GO"}
declare_test!{StateTests_RandomTests_st201503122204GO, "StateTests/RandomTests/st201503122204GO"}
declare_test!{StateTests_RandomTests_st201503122212GO, "StateTests/RandomTests/st201503122212GO"}
declare_test!{StateTests_RandomTests_st201503122231GO, "StateTests/RandomTests/st201503122231GO"}
declare_test!{StateTests_RandomTests_st201503122238GO, "StateTests/RandomTests/st201503122238GO"}
declare_test!{StateTests_RandomTests_st201503122252GO, "StateTests/RandomTests/st201503122252GO"}
declare_test!{StateTests_RandomTests_st201503122316GO, "StateTests/RandomTests/st201503122316GO"}
declare_test!{StateTests_RandomTests_st201503122324GO, "StateTests/RandomTests/st201503122324GO"}
declare_test!{StateTests_RandomTests_st201503122358GO, "StateTests/RandomTests/st201503122358GO"}
declare_test!{StateTests_RandomTests_st201503130002GO, "StateTests/RandomTests/st201503130002GO"}
declare_test!{StateTests_RandomTests_st201503130005GO, "StateTests/RandomTests/st201503130005GO"}
declare_test!{StateTests_RandomTests_st201503130007GO, "StateTests/RandomTests/st201503130007GO"}
declare_test!{StateTests_RandomTests_st201503130010GO, "StateTests/RandomTests/st201503130010GO"}
declare_test!{StateTests_RandomTests_st201503130023PYTHON, "StateTests/RandomTests/st201503130023PYTHON"}
declare_test!{StateTests_RandomTests_st201503130059GO, "StateTests/RandomTests/st201503130059GO"}
declare_test!{StateTests_RandomTests_st201503130101GO, "StateTests/RandomTests/st201503130101GO"}
declare_test!{StateTests_RandomTests_st201503130109GO, "StateTests/RandomTests/st201503130109GO"}
declare_test!{StateTests_RandomTests_st201503130117GO, "StateTests/RandomTests/st201503130117GO"}
declare_test!{StateTests_RandomTests_st201503130122GO, "StateTests/RandomTests/st201503130122GO"}
declare_test!{StateTests_RandomTests_st201503130156GO, "StateTests/RandomTests/st201503130156GO"}
declare_test!{StateTests_RandomTests_st201503130156PYTHON, "StateTests/RandomTests/st201503130156PYTHON"}
declare_test!{StateTests_RandomTests_st201503130207GO, "StateTests/RandomTests/st201503130207GO"}
declare_test!{StateTests_RandomTests_st201503130219CPPJIT, "StateTests/RandomTests/st201503130219CPPJIT"}
declare_test!{StateTests_RandomTests_st201503130219GO, "StateTests/RandomTests/st201503130219GO"}
declare_test!{StateTests_RandomTests_st201503130243GO, "StateTests/RandomTests/st201503130243GO"}
declare_test!{StateTests_RandomTests_st201503130246GO, "StateTests/RandomTests/st201503130246GO"}
declare_test!{StateTests_RandomTests_st201503130321GO, "StateTests/RandomTests/st201503130321GO"}
declare_test!{StateTests_RandomTests_st201503130322GO, "StateTests/RandomTests/st201503130322GO"}
declare_test!{StateTests_RandomTests_st201503130332GO, "StateTests/RandomTests/st201503130332GO"}
declare_test!{StateTests_RandomTests_st201503130359GO, "StateTests/RandomTests/st201503130359GO"}
declare_test!{StateTests_RandomTests_st201503130405GO, "StateTests/RandomTests/st201503130405GO"}
declare_test!{StateTests_RandomTests_st201503130408GO, "StateTests/RandomTests/st201503130408GO"}
declare_test!{StateTests_RandomTests_st201503130411GO, "StateTests/RandomTests/st201503130411GO"}
declare_test!{StateTests_RandomTests_st201503130431GO, "StateTests/RandomTests/st201503130431GO"}
declare_test!{StateTests_RandomTests_st201503130437GO, "StateTests/RandomTests/st201503130437GO"}
declare_test!{StateTests_RandomTests_st201503130450GO, "StateTests/RandomTests/st201503130450GO"}
declare_test!{StateTests_RandomTests_st201503130512CPPJIT, "StateTests/RandomTests/st201503130512CPPJIT"}
declare_test!{StateTests_RandomTests_st201503130512GO, "StateTests/RandomTests/st201503130512GO"}
declare_test!{StateTests_RandomTests_st201503130615GO, "StateTests/RandomTests/st201503130615GO"}
declare_test!{StateTests_RandomTests_st201503130705GO, "StateTests/RandomTests/st201503130705GO"}
declare_test!{StateTests_RandomTests_st201503130733CPPJIT, "StateTests/RandomTests/st201503130733CPPJIT"}
declare_test!{StateTests_RandomTests_st201503130733GO, "StateTests/RandomTests/st201503130733GO"}
declare_test!{StateTests_RandomTests_st201503130747GO, "StateTests/RandomTests/st201503130747GO"}
declare_test!{StateTests_RandomTests_st201503130751GO, "StateTests/RandomTests/st201503130751GO"}
declare_test!{StateTests_RandomTests_st201503130752PYTHON, "StateTests/RandomTests/st201503130752PYTHON"}
declare_test!{StateTests_RandomTests_st201503130757PYTHON, "StateTests/RandomTests/st201503130757PYTHON"}
declare_test!{StateTests_RandomTests_st201503131658GO, "StateTests/RandomTests/st201503131658GO"}
declare_test!{StateTests_RandomTests_st201503131739GO, "StateTests/RandomTests/st201503131739GO"}
declare_test!{StateTests_RandomTests_st201503131755CPPJIT, "StateTests/RandomTests/st201503131755CPPJIT"}
declare_test!{StateTests_RandomTests_st201503131755GO, "StateTests/RandomTests/st201503131755GO"}
declare_test!{StateTests_RandomTests_st201503132001CPPJIT, "StateTests/RandomTests/st201503132001CPPJIT"}
declare_test!{StateTests_RandomTests_st201503132127PYTHON, "StateTests/RandomTests/st201503132127PYTHON"}
declare_test!{StateTests_RandomTests_st201503132201CPPJIT, "StateTests/RandomTests/st201503132201CPPJIT"}
declare_test!{StateTests_RandomTests_st201503132201GO, "StateTests/RandomTests/st201503132201GO"}
declare_test!{StateTests_RandomTests_st201503132202PYTHON, "StateTests/RandomTests/st201503132202PYTHON"}
declare_test!{StateTests_RandomTests_st201503140002PYTHON, "StateTests/RandomTests/st201503140002PYTHON"}
declare_test!{StateTests_RandomTests_st201503140240PYTHON, "StateTests/RandomTests/st201503140240PYTHON"}
declare_test!{StateTests_RandomTests_st201503140522PYTHON, "StateTests/RandomTests/st201503140522PYTHON"}
declare_test!{StateTests_RandomTests_st201503140756PYTHON, "StateTests/RandomTests/st201503140756PYTHON"}
declare_test!{StateTests_RandomTests_st201503141144PYTHON, "StateTests/RandomTests/st201503141144PYTHON"}
declare_test!{StateTests_RandomTests_st201503141510PYTHON, "StateTests/RandomTests/st201503141510PYTHON"}
declare_test!{StateTests_RandomTests_st201503150427PYTHON, "StateTests/RandomTests/st201503150427PYTHON"}
declare_test!{StateTests_RandomTests_st201503150716PYTHON, "StateTests/RandomTests/st201503150716PYTHON"}
declare_test!{StateTests_RandomTests_st201503151450PYTHON, "StateTests/RandomTests/st201503151450PYTHON"}
declare_test!{StateTests_RandomTests_st201503151516PYTHON, "StateTests/RandomTests/st201503151516PYTHON"}
declare_test!{StateTests_RandomTests_st201503151753PYTHON, "StateTests/RandomTests/st201503151753PYTHON"}
declare_test!{StateTests_RandomTests_st201503152057PYTHON, "StateTests/RandomTests/st201503152057PYTHON"}
declare_test!{StateTests_RandomTests_st201503152241PYTHON, "StateTests/RandomTests/st201503152241PYTHON"}
declare_test!{StateTests_RandomTests_st201503160014PYTHON, "StateTests/RandomTests/st201503160014PYTHON"}
declare_test!{StateTests_RandomTests_st201503160733PYTHON, "StateTests/RandomTests/st201503160733PYTHON"}
declare_test!{StateTests_RandomTests_st201503170051PYTHON, "StateTests/RandomTests/st201503170051PYTHON"}
declare_test!{StateTests_RandomTests_st201503170433PYTHON, "StateTests/RandomTests/st201503170433PYTHON"}
declare_test!{StateTests_RandomTests_st201503170523PYTHON, "StateTests/RandomTests/st201503170523PYTHON"}
declare_test!{StateTests_RandomTests_st201503171108PYTHON, "StateTests/RandomTests/st201503171108PYTHON"}
declare_test!{StateTests_RandomTests_st201503181223GO, "StateTests/RandomTests/st201503181223GO"}
declare_test!{StateTests_RandomTests_st201503181225GO, "StateTests/RandomTests/st201503181225GO"}
declare_test!{StateTests_RandomTests_st201503181226CPPJIT, "StateTests/RandomTests/st201503181226CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181227CPPJIT, "StateTests/RandomTests/st201503181227CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181227GO, "StateTests/RandomTests/st201503181227GO"}
declare_test!{StateTests_RandomTests_st201503181229GO, "StateTests/RandomTests/st201503181229GO"}
declare_test!{StateTests_RandomTests_st201503181230CPPJIT, "StateTests/RandomTests/st201503181230CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181230GO, "StateTests/RandomTests/st201503181230GO"}
declare_test!{StateTests_RandomTests_st201503181231GO, "StateTests/RandomTests/st201503181231GO"}
declare_test!{StateTests_RandomTests_st201503181232CPPJIT, "StateTests/RandomTests/st201503181232CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181232GO, "StateTests/RandomTests/st201503181232GO"}
declare_test!{StateTests_RandomTests_st201503181233GO, "StateTests/RandomTests/st201503181233GO"}
declare_test!{StateTests_RandomTests_st201503181234CPPJIT, "StateTests/RandomTests/st201503181234CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181234GO, "StateTests/RandomTests/st201503181234GO"}
declare_test!{StateTests_RandomTests_st201503181235CPPJIT, "StateTests/RandomTests/st201503181235CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181235GO, "StateTests/RandomTests/st201503181235GO"}
declare_test!{StateTests_RandomTests_st201503181236GO, "StateTests/RandomTests/st201503181236GO"}
declare_test!{StateTests_RandomTests_st201503181237GO, "StateTests/RandomTests/st201503181237GO"}
declare_test!{StateTests_RandomTests_st201503181239GO, "StateTests/RandomTests/st201503181239GO"}
declare_test!{StateTests_RandomTests_st201503181241CPPJIT, "StateTests/RandomTests/st201503181241CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181241GO, "StateTests/RandomTests/st201503181241GO"}
declare_test!{StateTests_RandomTests_st201503181243GO, "StateTests/RandomTests/st201503181243GO"}
declare_test!{StateTests_RandomTests_st201503181244GO, "StateTests/RandomTests/st201503181244GO"}
declare_test!{StateTests_RandomTests_st201503181245CPPJIT, "StateTests/RandomTests/st201503181245CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181245GO, "StateTests/RandomTests/st201503181245GO"}
declare_test!{StateTests_RandomTests_st201503181246CPPJIT, "StateTests/RandomTests/st201503181246CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181246GO, "StateTests/RandomTests/st201503181246GO"}
declare_test!{StateTests_RandomTests_st201503181247GO, "StateTests/RandomTests/st201503181247GO"}
declare_test!{StateTests_RandomTests_st201503181248GO, "StateTests/RandomTests/st201503181248GO"}
declare_test!{StateTests_RandomTests_st201503181249GO, "StateTests/RandomTests/st201503181249GO"}
declare_test!{StateTests_RandomTests_st201503181250CPPJIT, "StateTests/RandomTests/st201503181250CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181250GO, "StateTests/RandomTests/st201503181250GO"}
declare_test!{StateTests_RandomTests_st201503181251GO, "StateTests/RandomTests/st201503181251GO"}
declare_test!{StateTests_RandomTests_st201503181252CPPJIT, "StateTests/RandomTests/st201503181252CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181253GO, "StateTests/RandomTests/st201503181253GO"}
declare_test!{StateTests_RandomTests_st201503181255CPPJIT, "StateTests/RandomTests/st201503181255CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181255GO, "StateTests/RandomTests/st201503181255GO"}
declare_test!{StateTests_RandomTests_st201503181257GO, "StateTests/RandomTests/st201503181257GO"}
declare_test!{StateTests_RandomTests_st201503181258CPPJIT, "StateTests/RandomTests/st201503181258CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181258GO, "StateTests/RandomTests/st201503181258GO"}
declare_test!{StateTests_RandomTests_st201503181301CPPJIT, "StateTests/RandomTests/st201503181301CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181301GO, "StateTests/RandomTests/st201503181301GO"}
declare_test!{StateTests_RandomTests_st201503181303GO, "StateTests/RandomTests/st201503181303GO"}
declare_test!{StateTests_RandomTests_st201503181304GO, "StateTests/RandomTests/st201503181304GO"}
declare_test!{StateTests_RandomTests_st201503181305GO, "StateTests/RandomTests/st201503181305GO"}
declare_test!{StateTests_RandomTests_st201503181306GO, "StateTests/RandomTests/st201503181306GO"}
declare_test!{StateTests_RandomTests_st201503181307CPPJIT, "StateTests/RandomTests/st201503181307CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181307GO, "StateTests/RandomTests/st201503181307GO"}
declare_test!{StateTests_RandomTests_st201503181308GO, "StateTests/RandomTests/st201503181308GO"}
declare_test!{StateTests_RandomTests_st201503181309GO, "StateTests/RandomTests/st201503181309GO"}
declare_test!{StateTests_RandomTests_st201503181310GO, "StateTests/RandomTests/st201503181310GO"}
declare_test!{StateTests_RandomTests_st201503181311GO, "StateTests/RandomTests/st201503181311GO"}
declare_test!{StateTests_RandomTests_st201503181313GO, "StateTests/RandomTests/st201503181313GO"}
declare_test!{StateTests_RandomTests_st201503181314GO, "StateTests/RandomTests/st201503181314GO"}
declare_test!{StateTests_RandomTests_st201503181315CPPJIT, "StateTests/RandomTests/st201503181315CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181315GO, "StateTests/RandomTests/st201503181315GO"}
declare_test!{StateTests_RandomTests_st201503181316CPPJIT, "StateTests/RandomTests/st201503181316CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181316PYTHON, "StateTests/RandomTests/st201503181316PYTHON"}
declare_test!{StateTests_RandomTests_st201503181317GO, "StateTests/RandomTests/st201503181317GO"}
declare_test!{StateTests_RandomTests_st201503181318CPPJIT, "StateTests/RandomTests/st201503181318CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181318GO, "StateTests/RandomTests/st201503181318GO"}
declare_test!{StateTests_RandomTests_st201503181319GO, "StateTests/RandomTests/st201503181319GO"}
declare_test!{StateTests_RandomTests_st201503181319PYTHON, "StateTests/RandomTests/st201503181319PYTHON"}
declare_test!{StateTests_RandomTests_st201503181322GO, "StateTests/RandomTests/st201503181322GO"}
declare_test!{StateTests_RandomTests_st201503181323CPPJIT, "StateTests/RandomTests/st201503181323CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181323GO, "StateTests/RandomTests/st201503181323GO"}
declare_test!{StateTests_RandomTests_st201503181324GO, "StateTests/RandomTests/st201503181324GO"}
declare_test!{StateTests_RandomTests_st201503181325GO, "StateTests/RandomTests/st201503181325GO"}
declare_test!{StateTests_RandomTests_st201503181326CPPJIT, "StateTests/RandomTests/st201503181326CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181326GO, "StateTests/RandomTests/st201503181326GO"}
declare_test!{StateTests_RandomTests_st201503181327GO, "StateTests/RandomTests/st201503181327GO"}
declare_test!{StateTests_RandomTests_st201503181329CPPJIT, "StateTests/RandomTests/st201503181329CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181329GO, "StateTests/RandomTests/st201503181329GO"}
declare_test!{StateTests_RandomTests_st201503181330GO, "StateTests/RandomTests/st201503181330GO"}
declare_test!{StateTests_RandomTests_st201503181332GO, "StateTests/RandomTests/st201503181332GO"}
declare_test!{StateTests_RandomTests_st201503181333GO, "StateTests/RandomTests/st201503181333GO"}
declare_test!{StateTests_RandomTests_st201503181334GO, "StateTests/RandomTests/st201503181334GO"}
declare_test!{StateTests_RandomTests_st201503181336CPPJIT, "StateTests/RandomTests/st201503181336CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181337GO, "StateTests/RandomTests/st201503181337GO"}
declare_test!{StateTests_RandomTests_st201503181338GO, "StateTests/RandomTests/st201503181338GO"}
declare_test!{StateTests_RandomTests_st201503181339CPPJIT, "StateTests/RandomTests/st201503181339CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181339GO, "StateTests/RandomTests/st201503181339GO"}
declare_test!{StateTests_RandomTests_st201503181340GO, "StateTests/RandomTests/st201503181340GO"}
declare_test!{StateTests_RandomTests_st201503181341CPPJIT, "StateTests/RandomTests/st201503181341CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181342CPPJIT, "StateTests/RandomTests/st201503181342CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181342GO, "StateTests/RandomTests/st201503181342GO"}
declare_test!{StateTests_RandomTests_st201503181345GO, "StateTests/RandomTests/st201503181345GO"}
declare_test!{StateTests_RandomTests_st201503181346GO, "StateTests/RandomTests/st201503181346GO"}
declare_test!{StateTests_RandomTests_st201503181347CPPJIT, "StateTests/RandomTests/st201503181347CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181347GO, "StateTests/RandomTests/st201503181347GO"}
declare_test!{StateTests_RandomTests_st201503181347PYTHON, "StateTests/RandomTests/st201503181347PYTHON"}
declare_test!{StateTests_RandomTests_st201503181350CPPJIT, "StateTests/RandomTests/st201503181350CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181352GO, "StateTests/RandomTests/st201503181352GO"}
declare_test!{StateTests_RandomTests_st201503181353GO, "StateTests/RandomTests/st201503181353GO"}
declare_test!{StateTests_RandomTests_st201503181354CPPJIT, "StateTests/RandomTests/st201503181354CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181354GO, "StateTests/RandomTests/st201503181354GO"}
declare_test!{StateTests_RandomTests_st201503181355GO, "StateTests/RandomTests/st201503181355GO"}
declare_test!{StateTests_RandomTests_st201503181356CPPJIT, "StateTests/RandomTests/st201503181356CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181357CPPJIT, "StateTests/RandomTests/st201503181357CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181358CPPJIT, "StateTests/RandomTests/st201503181358CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181358GO, "StateTests/RandomTests/st201503181358GO"}
declare_test!{StateTests_RandomTests_st201503181359GO, "StateTests/RandomTests/st201503181359GO"}
declare_test!{StateTests_RandomTests_st201503181402CPPJIT, "StateTests/RandomTests/st201503181402CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181403GO, "StateTests/RandomTests/st201503181403GO"}
declare_test!{StateTests_RandomTests_st201503181406CPPJIT, "StateTests/RandomTests/st201503181406CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181406GO, "StateTests/RandomTests/st201503181406GO"}
declare_test!{StateTests_RandomTests_st201503181410GO, "StateTests/RandomTests/st201503181410GO"}
declare_test!{StateTests_RandomTests_st201503181412CPPJIT, "StateTests/RandomTests/st201503181412CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181413GO, "StateTests/RandomTests/st201503181413GO"}
declare_test!{StateTests_RandomTests_st201503181415GO, "StateTests/RandomTests/st201503181415GO"}
declare_test!{StateTests_RandomTests_st201503181416GO, "StateTests/RandomTests/st201503181416GO"}
declare_test!{StateTests_RandomTests_st201503181417CPPJIT, "StateTests/RandomTests/st201503181417CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181417GO, "StateTests/RandomTests/st201503181417GO"}
declare_test!{StateTests_RandomTests_st201503181418CPPJIT, "StateTests/RandomTests/st201503181418CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181422GO, "StateTests/RandomTests/st201503181422GO"}
declare_test!{StateTests_RandomTests_st201503181423CPPJIT, "StateTests/RandomTests/st201503181423CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181424GO, "StateTests/RandomTests/st201503181424GO"}
declare_test!{StateTests_RandomTests_st201503181426CPPJIT, "StateTests/RandomTests/st201503181426CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181426GO, "StateTests/RandomTests/st201503181426GO"}
declare_test!{StateTests_RandomTests_st201503181428GO, "StateTests/RandomTests/st201503181428GO"}
declare_test!{StateTests_RandomTests_st201503181430CPPJIT, "StateTests/RandomTests/st201503181430CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181435GO, "StateTests/RandomTests/st201503181435GO"}
declare_test!{StateTests_RandomTests_st201503181436GO, "StateTests/RandomTests/st201503181436GO"}
declare_test!{StateTests_RandomTests_st201503181437CPPJIT, "StateTests/RandomTests/st201503181437CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181437GO, "StateTests/RandomTests/st201503181437GO"}
declare_test!{StateTests_RandomTests_st201503181438CPPJIT, "StateTests/RandomTests/st201503181438CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181438GO, "StateTests/RandomTests/st201503181438GO"}
declare_test!{StateTests_RandomTests_st201503181439CPPJIT, "StateTests/RandomTests/st201503181439CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181439GO, "StateTests/RandomTests/st201503181439GO"}
declare_test!{StateTests_RandomTests_st201503181439PYTHON, "StateTests/RandomTests/st201503181439PYTHON"}
declare_test!{StateTests_RandomTests_st201503181440GO, "StateTests/RandomTests/st201503181440GO"}
declare_test!{StateTests_RandomTests_st201503181441GO, "StateTests/RandomTests/st201503181441GO"}
declare_test!{StateTests_RandomTests_st201503181442GO, "StateTests/RandomTests/st201503181442GO"}
declare_test!{StateTests_RandomTests_st201503181445CPPJIT, "StateTests/RandomTests/st201503181445CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181446GO, "StateTests/RandomTests/st201503181446GO"}
declare_test!{StateTests_RandomTests_st201503181447GO, "StateTests/RandomTests/st201503181447GO"}
declare_test!{StateTests_RandomTests_st201503181450GO, "StateTests/RandomTests/st201503181450GO"}
declare_test!{StateTests_RandomTests_st201503181451CPPJIT, "StateTests/RandomTests/st201503181451CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181453GO, "StateTests/RandomTests/st201503181453GO"}
declare_test!{StateTests_RandomTests_st201503181455GO, "StateTests/RandomTests/st201503181455GO"}
declare_test!{StateTests_RandomTests_st201503181456CPPJIT, "StateTests/RandomTests/st201503181456CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181457GO, "StateTests/RandomTests/st201503181457GO"}
declare_test!{StateTests_RandomTests_st201503181458GO, "StateTests/RandomTests/st201503181458GO"}
declare_test!{StateTests_RandomTests_st201503181459GO, "StateTests/RandomTests/st201503181459GO"}
declare_test!{StateTests_RandomTests_st201503181500GO, "StateTests/RandomTests/st201503181500GO"}
declare_test!{StateTests_RandomTests_st201503181501GO, "StateTests/RandomTests/st201503181501GO"}
declare_test!{StateTests_RandomTests_st201503181503GO, "StateTests/RandomTests/st201503181503GO"}
declare_test!{StateTests_RandomTests_st201503181504GO, "StateTests/RandomTests/st201503181504GO"}
declare_test!{StateTests_RandomTests_st201503181505GO, "StateTests/RandomTests/st201503181505GO"}
declare_test!{StateTests_RandomTests_st201503181506CPPJIT, "StateTests/RandomTests/st201503181506CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181507GO, "StateTests/RandomTests/st201503181507GO"}
declare_test!{StateTests_RandomTests_st201503181509CPPJIT, "StateTests/RandomTests/st201503181509CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181509GO, "StateTests/RandomTests/st201503181509GO"}
declare_test!{StateTests_RandomTests_st201503181510GO, "StateTests/RandomTests/st201503181510GO"}
declare_test!{StateTests_RandomTests_st201503181511GO, "StateTests/RandomTests/st201503181511GO"}
declare_test!{StateTests_RandomTests_st201503181512GO, "StateTests/RandomTests/st201503181512GO"}
declare_test!{StateTests_RandomTests_st201503181513CPPJIT, "StateTests/RandomTests/st201503181513CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181513GO, "StateTests/RandomTests/st201503181513GO"}
declare_test!{StateTests_RandomTests_st201503181514CPPJIT, "StateTests/RandomTests/st201503181514CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181514GO, "StateTests/RandomTests/st201503181514GO"}
declare_test!{StateTests_RandomTests_st201503181517CPPJIT, "StateTests/RandomTests/st201503181517CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181517GO, "StateTests/RandomTests/st201503181517GO"}
declare_test!{StateTests_RandomTests_st201503181519CPPJIT, "StateTests/RandomTests/st201503181519CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181519GO, "StateTests/RandomTests/st201503181519GO"}
declare_test!{StateTests_RandomTests_st201503181520CPPJIT, "StateTests/RandomTests/st201503181520CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181520GO, "StateTests/RandomTests/st201503181520GO"}
declare_test!{StateTests_RandomTests_st201503181521GO, "StateTests/RandomTests/st201503181521GO"}
declare_test!{StateTests_RandomTests_st201503181522GO, "StateTests/RandomTests/st201503181522GO"}
declare_test!{StateTests_RandomTests_st201503181524CPPJIT, "StateTests/RandomTests/st201503181524CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181524GO, "StateTests/RandomTests/st201503181524GO"}
declare_test!{StateTests_RandomTests_st201503181526GO, "StateTests/RandomTests/st201503181526GO"}
declare_test!{StateTests_RandomTests_st201503181527GO, "StateTests/RandomTests/st201503181527GO"}
declare_test!{StateTests_RandomTests_st201503181528CPPJIT, "StateTests/RandomTests/st201503181528CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181528GO, "StateTests/RandomTests/st201503181528GO"}
declare_test!{StateTests_RandomTests_st201503181528PYTHON, "StateTests/RandomTests/st201503181528PYTHON"}
declare_test!{StateTests_RandomTests_st201503181529GO, "StateTests/RandomTests/st201503181529GO"}
declare_test!{StateTests_RandomTests_st201503181531CPPJIT, "StateTests/RandomTests/st201503181531CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181533GO, "StateTests/RandomTests/st201503181533GO"}
declare_test!{StateTests_RandomTests_st201503181534CPPJIT, "StateTests/RandomTests/st201503181534CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181534GO, "StateTests/RandomTests/st201503181534GO"}
declare_test!{StateTests_RandomTests_st201503181536CPPJIT, "StateTests/RandomTests/st201503181536CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181536GO, "StateTests/RandomTests/st201503181536GO"}
declare_test!{StateTests_RandomTests_st201503181537GO, "StateTests/RandomTests/st201503181537GO"}
declare_test!{StateTests_RandomTests_st201503181538GO, "StateTests/RandomTests/st201503181538GO"}
declare_test!{StateTests_RandomTests_st201503181539GO, "StateTests/RandomTests/st201503181539GO"}
declare_test!{StateTests_RandomTests_st201503181540CPPJIT, "StateTests/RandomTests/st201503181540CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181540PYTHON, "StateTests/RandomTests/st201503181540PYTHON"}
declare_test!{StateTests_RandomTests_st201503181543GO, "StateTests/RandomTests/st201503181543GO"}
declare_test!{StateTests_RandomTests_st201503181544CPPJIT, "StateTests/RandomTests/st201503181544CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181544GO, "StateTests/RandomTests/st201503181544GO"}
declare_test!{StateTests_RandomTests_st201503181547GO, "StateTests/RandomTests/st201503181547GO"}
declare_test!{StateTests_RandomTests_st201503181548CPPJIT, "StateTests/RandomTests/st201503181548CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181548GO, "StateTests/RandomTests/st201503181548GO"}
declare_test!{StateTests_RandomTests_st201503181551GO, "StateTests/RandomTests/st201503181551GO"}
declare_test!{StateTests_RandomTests_st201503181552CPPJIT, "StateTests/RandomTests/st201503181552CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181553GO, "StateTests/RandomTests/st201503181553GO"}
declare_test!{StateTests_RandomTests_st201503181555CPPJIT, "StateTests/RandomTests/st201503181555CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181555GO, "StateTests/RandomTests/st201503181555GO"}
declare_test!{StateTests_RandomTests_st201503181557GO, "StateTests/RandomTests/st201503181557GO"}
declare_test!{StateTests_RandomTests_st201503181559GO, "StateTests/RandomTests/st201503181559GO"}
declare_test!{StateTests_RandomTests_st201503181601CPPJIT, "StateTests/RandomTests/st201503181601CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181601GO, "StateTests/RandomTests/st201503181601GO"}
declare_test!{StateTests_RandomTests_st201503181602GO, "StateTests/RandomTests/st201503181602GO"}
declare_test!{StateTests_RandomTests_st201503181603GO, "StateTests/RandomTests/st201503181603GO"}
declare_test!{StateTests_RandomTests_st201503181604GO, "StateTests/RandomTests/st201503181604GO"}
declare_test!{StateTests_RandomTests_st201503181605GO, "StateTests/RandomTests/st201503181605GO"}
declare_test!{StateTests_RandomTests_st201503181606GO, "StateTests/RandomTests/st201503181606GO"}
declare_test!{StateTests_RandomTests_st201503181607GO, "StateTests/RandomTests/st201503181607GO"}
declare_test!{StateTests_RandomTests_st201503181608CPPJIT, "StateTests/RandomTests/st201503181608CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181608GO, "StateTests/RandomTests/st201503181608GO"}
declare_test!{StateTests_RandomTests_st201503181609GO, "StateTests/RandomTests/st201503181609GO"}
declare_test!{StateTests_RandomTests_st201503181610CPPJIT, "StateTests/RandomTests/st201503181610CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181610GO, "StateTests/RandomTests/st201503181610GO"}
declare_test!{StateTests_RandomTests_st201503181611CPPJIT, "StateTests/RandomTests/st201503181611CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181611GO, "StateTests/RandomTests/st201503181611GO"}
declare_test!{StateTests_RandomTests_st201503181612GO, "StateTests/RandomTests/st201503181612GO"}
declare_test!{StateTests_RandomTests_st201503181614CPPJIT, "StateTests/RandomTests/st201503181614CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181614GO, "StateTests/RandomTests/st201503181614GO"}
declare_test!{StateTests_RandomTests_st201503181616CPPJIT, "StateTests/RandomTests/st201503181616CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181616GO, "StateTests/RandomTests/st201503181616GO"}
declare_test!{StateTests_RandomTests_st201503181617GO, "StateTests/RandomTests/st201503181617GO"}
declare_test!{StateTests_RandomTests_st201503181618GO, "StateTests/RandomTests/st201503181618GO"}
declare_test!{StateTests_RandomTests_st201503181619GO, "StateTests/RandomTests/st201503181619GO"}
declare_test!{StateTests_RandomTests_st201503181620CPPJIT, "StateTests/RandomTests/st201503181620CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181620GO, "StateTests/RandomTests/st201503181620GO"}
declare_test!{StateTests_RandomTests_st201503181621GO, "StateTests/RandomTests/st201503181621GO"}
declare_test!{StateTests_RandomTests_st201503181625GO, "StateTests/RandomTests/st201503181625GO"}
declare_test!{StateTests_RandomTests_st201503181626CPPJIT, "StateTests/RandomTests/st201503181626CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181626GO, "StateTests/RandomTests/st201503181626GO"}
declare_test!{StateTests_RandomTests_st201503181627GO, "StateTests/RandomTests/st201503181627GO"}
declare_test!{StateTests_RandomTests_st201503181628GO, "StateTests/RandomTests/st201503181628GO"}
declare_test!{StateTests_RandomTests_st201503181629GO, "StateTests/RandomTests/st201503181629GO"}
declare_test!{StateTests_RandomTests_st201503181630CPPJIT, "StateTests/RandomTests/st201503181630CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181630GO, "StateTests/RandomTests/st201503181630GO"}
declare_test!{StateTests_RandomTests_st201503181630PYTHON, "StateTests/RandomTests/st201503181630PYTHON"}
declare_test!{StateTests_RandomTests_st201503181632GO, "StateTests/RandomTests/st201503181632GO"}
declare_test!{StateTests_RandomTests_st201503181634CPPJIT, "StateTests/RandomTests/st201503181634CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181635GO, "StateTests/RandomTests/st201503181635GO"}
declare_test!{StateTests_RandomTests_st201503181636GO, "StateTests/RandomTests/st201503181636GO"}
declare_test!{StateTests_RandomTests_st201503181638GO, "StateTests/RandomTests/st201503181638GO"}
declare_test!{StateTests_RandomTests_st201503181639CPPJIT, "StateTests/RandomTests/st201503181639CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181641GO, "StateTests/RandomTests/st201503181641GO"}
declare_test!{StateTests_RandomTests_st201503181645GO, "StateTests/RandomTests/st201503181645GO"}
declare_test!{StateTests_RandomTests_st201503181646GO, "StateTests/RandomTests/st201503181646GO"}
declare_test!{StateTests_RandomTests_st201503181647CPPJIT, "StateTests/RandomTests/st201503181647CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181649CPPJIT, "StateTests/RandomTests/st201503181649CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181650GO, "StateTests/RandomTests/st201503181650GO"}
declare_test!{StateTests_RandomTests_st201503181652CPPJIT, "StateTests/RandomTests/st201503181652CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181653GO, "StateTests/RandomTests/st201503181653GO"}
declare_test!{StateTests_RandomTests_st201503181654GO, "StateTests/RandomTests/st201503181654GO"}
declare_test!{StateTests_RandomTests_st201503181655CPPJIT, "StateTests/RandomTests/st201503181655CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181655GO, "StateTests/RandomTests/st201503181655GO"}
declare_test!{StateTests_RandomTests_st201503181656CPPJIT, "StateTests/RandomTests/st201503181656CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181656GO, "StateTests/RandomTests/st201503181656GO"}
declare_test!{StateTests_RandomTests_st201503181657GO, "StateTests/RandomTests/st201503181657GO"}
declare_test!{StateTests_RandomTests_st201503181658GO, "StateTests/RandomTests/st201503181658GO"}
declare_test!{StateTests_RandomTests_st201503181700GO, "StateTests/RandomTests/st201503181700GO"}
declare_test!{StateTests_RandomTests_st201503181702GO, "StateTests/RandomTests/st201503181702GO"}
declare_test!{StateTests_RandomTests_st201503181703CPPJIT, "StateTests/RandomTests/st201503181703CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181703GO, "StateTests/RandomTests/st201503181703GO"}
declare_test!{StateTests_RandomTests_st201503181704GO, "StateTests/RandomTests/st201503181704GO"}
declare_test!{StateTests_RandomTests_st201503181706GO, "StateTests/RandomTests/st201503181706GO"}
declare_test!{StateTests_RandomTests_st201503181709GO, "StateTests/RandomTests/st201503181709GO"}
declare_test!{StateTests_RandomTests_st201503181711CPPJIT, "StateTests/RandomTests/st201503181711CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181711GO, "StateTests/RandomTests/st201503181711GO"}
declare_test!{StateTests_RandomTests_st201503181713CPPJIT, "StateTests/RandomTests/st201503181713CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181713GO, "StateTests/RandomTests/st201503181713GO"}
declare_test!{StateTests_RandomTests_st201503181714GO, "StateTests/RandomTests/st201503181714GO"}
declare_test!{StateTests_RandomTests_st201503181715CPPJIT, "StateTests/RandomTests/st201503181715CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181715GO, "StateTests/RandomTests/st201503181715GO"}
declare_test!{StateTests_RandomTests_st201503181716GO, "StateTests/RandomTests/st201503181716GO"}
declare_test!{StateTests_RandomTests_st201503181717GO, "StateTests/RandomTests/st201503181717GO"}
declare_test!{StateTests_RandomTests_st201503181720CPPJIT, "StateTests/RandomTests/st201503181720CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181722GO, "StateTests/RandomTests/st201503181722GO"}
declare_test!{StateTests_RandomTests_st201503181723CPPJIT, "StateTests/RandomTests/st201503181723CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181723GO, "StateTests/RandomTests/st201503181723GO"}
declare_test!{StateTests_RandomTests_st201503181724CPPJIT, "StateTests/RandomTests/st201503181724CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181724GO, "StateTests/RandomTests/st201503181724GO"}
declare_test!{StateTests_RandomTests_st201503181725GO, "StateTests/RandomTests/st201503181725GO"}
declare_test!{StateTests_RandomTests_st201503181728GO, "StateTests/RandomTests/st201503181728GO"}
declare_test!{StateTests_RandomTests_st201503181729GO, "StateTests/RandomTests/st201503181729GO"}
declare_test!{StateTests_RandomTests_st201503181730GO, "StateTests/RandomTests/st201503181730GO"}
declare_test!{StateTests_RandomTests_st201503181731CPPJIT, "StateTests/RandomTests/st201503181731CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181732GO, "StateTests/RandomTests/st201503181732GO"}
declare_test!{StateTests_RandomTests_st201503181734CPPJIT, "StateTests/RandomTests/st201503181734CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181734GO, "StateTests/RandomTests/st201503181734GO"}
declare_test!{StateTests_RandomTests_st201503181735GO, "StateTests/RandomTests/st201503181735GO"}
declare_test!{StateTests_RandomTests_st201503181737CPPJIT, "StateTests/RandomTests/st201503181737CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181737GO, "StateTests/RandomTests/st201503181737GO"}
declare_test!{StateTests_RandomTests_st201503181738CPPJIT, "StateTests/RandomTests/st201503181738CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181738GO, "StateTests/RandomTests/st201503181738GO"}
declare_test!{StateTests_RandomTests_st201503181739GO, "StateTests/RandomTests/st201503181739GO"}
declare_test!{StateTests_RandomTests_st201503181740CPPJIT, "StateTests/RandomTests/st201503181740CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181740GO, "StateTests/RandomTests/st201503181740GO"}
declare_test!{StateTests_RandomTests_st201503181742CPPJIT, "StateTests/RandomTests/st201503181742CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181743GO, "StateTests/RandomTests/st201503181743GO"}
declare_test!{StateTests_RandomTests_st201503181744GO, "StateTests/RandomTests/st201503181744GO"}
declare_test!{StateTests_RandomTests_st201503181745CPPJIT, "StateTests/RandomTests/st201503181745CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181746GO, "StateTests/RandomTests/st201503181746GO"}
declare_test!{StateTests_RandomTests_st201503181747GO, "StateTests/RandomTests/st201503181747GO"}
declare_test!{StateTests_RandomTests_st201503181748GO, "StateTests/RandomTests/st201503181748GO"}
declare_test!{StateTests_RandomTests_st201503181749GO, "StateTests/RandomTests/st201503181749GO"}
declare_test!{StateTests_RandomTests_st201503181750CPPJIT, "StateTests/RandomTests/st201503181750CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181750GO, "StateTests/RandomTests/st201503181750GO"}
declare_test!{StateTests_RandomTests_st201503181752GO, "StateTests/RandomTests/st201503181752GO"}
declare_test!{StateTests_RandomTests_st201503181753CPPJIT, "StateTests/RandomTests/st201503181753CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181754CPPJIT, "StateTests/RandomTests/st201503181754CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181754GO, "StateTests/RandomTests/st201503181754GO"}
declare_test!{StateTests_RandomTests_st201503181755CPPJIT, "StateTests/RandomTests/st201503181755CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181755GO, "StateTests/RandomTests/st201503181755GO"}
declare_test!{StateTests_RandomTests_st201503181756GO, "StateTests/RandomTests/st201503181756GO"}
declare_test!{StateTests_RandomTests_st201503181757CPPJIT, "StateTests/RandomTests/st201503181757CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181757GO, "StateTests/RandomTests/st201503181757GO"}
declare_test!{StateTests_RandomTests_st201503181759GO, "StateTests/RandomTests/st201503181759GO"}
declare_test!{StateTests_RandomTests_st201503181800GO, "StateTests/RandomTests/st201503181800GO"}
declare_test!{StateTests_RandomTests_st201503181801GO, "StateTests/RandomTests/st201503181801GO"}
declare_test!{StateTests_RandomTests_st201503181802GO, "StateTests/RandomTests/st201503181802GO"}
declare_test!{StateTests_RandomTests_st201503181803CPPJIT, "StateTests/RandomTests/st201503181803CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181803GO, "StateTests/RandomTests/st201503181803GO"}
declare_test!{StateTests_RandomTests_st201503181804GO, "StateTests/RandomTests/st201503181804GO"}
declare_test!{StateTests_RandomTests_st201503181806GO, "StateTests/RandomTests/st201503181806GO"}
declare_test!{StateTests_RandomTests_st201503181808GO, "StateTests/RandomTests/st201503181808GO"}
declare_test!{StateTests_RandomTests_st201503181809CPPJIT, "StateTests/RandomTests/st201503181809CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181812CPPJIT, "StateTests/RandomTests/st201503181812CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181812GO, "StateTests/RandomTests/st201503181812GO"}
declare_test!{StateTests_RandomTests_st201503181814CPPJIT, "StateTests/RandomTests/st201503181814CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181815GO, "StateTests/RandomTests/st201503181815GO"}
declare_test!{StateTests_RandomTests_st201503181816CPPJIT, "StateTests/RandomTests/st201503181816CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181817CPPJIT, "StateTests/RandomTests/st201503181817CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181819GO, "StateTests/RandomTests/st201503181819GO"}
declare_test!{StateTests_RandomTests_st201503181821GO, "StateTests/RandomTests/st201503181821GO"}
declare_test!{StateTests_RandomTests_st201503181822GO, "StateTests/RandomTests/st201503181822GO"}
declare_test!{StateTests_RandomTests_st201503181823GO, "StateTests/RandomTests/st201503181823GO"}
declare_test!{StateTests_RandomTests_st201503181824GO, "StateTests/RandomTests/st201503181824GO"}
declare_test!{StateTests_RandomTests_st201503181825GO, "StateTests/RandomTests/st201503181825GO"}
declare_test!{StateTests_RandomTests_st201503181829GO, "StateTests/RandomTests/st201503181829GO"}
declare_test!{StateTests_RandomTests_st201503181830CPPJIT, "StateTests/RandomTests/st201503181830CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181833GO, "StateTests/RandomTests/st201503181833GO"}
declare_test!{StateTests_RandomTests_st201503181834CPPJIT, "StateTests/RandomTests/st201503181834CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181834GO, "StateTests/RandomTests/st201503181834GO"}
declare_test!{StateTests_RandomTests_st201503181837GO, "StateTests/RandomTests/st201503181837GO"}
declare_test!{StateTests_RandomTests_st201503181840GO, "StateTests/RandomTests/st201503181840GO"}
declare_test!{StateTests_RandomTests_st201503181842GO, "StateTests/RandomTests/st201503181842GO"}
declare_test!{StateTests_RandomTests_st201503181843GO, "StateTests/RandomTests/st201503181843GO"}
declare_test!{StateTests_RandomTests_st201503181844GO, "StateTests/RandomTests/st201503181844GO"}
declare_test!{StateTests_RandomTests_st201503181845GO, "StateTests/RandomTests/st201503181845GO"}
declare_test!{StateTests_RandomTests_st201503181846GO, "StateTests/RandomTests/st201503181846GO"}
declare_test!{StateTests_RandomTests_st201503181847GO, "StateTests/RandomTests/st201503181847GO"}
declare_test!{StateTests_RandomTests_st201503181848GO, "StateTests/RandomTests/st201503181848GO"}
declare_test!{StateTests_RandomTests_st201503181849GO, "StateTests/RandomTests/st201503181849GO"}
declare_test!{StateTests_RandomTests_st201503181850GO, "StateTests/RandomTests/st201503181850GO"}
declare_test!{StateTests_RandomTests_st201503181851CPPJIT, "StateTests/RandomTests/st201503181851CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181851GO, "StateTests/RandomTests/st201503181851GO"}
declare_test!{StateTests_RandomTests_st201503181852CPPJIT, "StateTests/RandomTests/st201503181852CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181854GO, "StateTests/RandomTests/st201503181854GO"}
declare_test!{StateTests_RandomTests_st201503181855CPPJIT, "StateTests/RandomTests/st201503181855CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181857PYTHON, "StateTests/RandomTests/st201503181857PYTHON"}
declare_test!{StateTests_RandomTests_st201503181859GO, "StateTests/RandomTests/st201503181859GO"}
declare_test!{StateTests_RandomTests_st201503181900GO, "StateTests/RandomTests/st201503181900GO"}
declare_test!{StateTests_RandomTests_st201503181903GO, "StateTests/RandomTests/st201503181903GO"}
declare_test!{StateTests_RandomTests_st201503181904GO, "StateTests/RandomTests/st201503181904GO"}
declare_test!{StateTests_RandomTests_st201503181906GO, "StateTests/RandomTests/st201503181906GO"}
declare_test!{StateTests_RandomTests_st201503181907GO, "StateTests/RandomTests/st201503181907GO"}
declare_test!{StateTests_RandomTests_st201503181910GO, "StateTests/RandomTests/st201503181910GO"}
declare_test!{StateTests_RandomTests_st201503181915GO, "StateTests/RandomTests/st201503181915GO"}
declare_test!{StateTests_RandomTests_st201503181919CPPJIT, "StateTests/RandomTests/st201503181919CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181919PYTHON, "StateTests/RandomTests/st201503181919PYTHON"}
declare_test!{StateTests_RandomTests_st201503181920GO, "StateTests/RandomTests/st201503181920GO"}
declare_test!{StateTests_RandomTests_st201503181922GO, "StateTests/RandomTests/st201503181922GO"}
declare_test!{StateTests_RandomTests_st201503181926GO, "StateTests/RandomTests/st201503181926GO"}
declare_test!{StateTests_RandomTests_st201503181929GO, "StateTests/RandomTests/st201503181929GO"}
declare_test!{StateTests_RandomTests_st201503181931CPPJIT, "StateTests/RandomTests/st201503181931CPPJIT"}
declare_test!{StateTests_RandomTests_st201503181931GO, "StateTests/RandomTests/st201503181931GO"}
declare_test!{StateTests_RandomTests_st201503181931PYTHON, "StateTests/RandomTests/st201503181931PYTHON"}
declare_test!{StateTests_RandomTests_st201503191646GO, "StateTests/RandomTests/st201503191646GO"}
declare_test!{StateTests_RandomTests_st201503200837JS, "StateTests/RandomTests/st201503200837JS"}
declare_test!{StateTests_RandomTests_st201503200838JS, "StateTests/RandomTests/st201503200838JS"}
declare_test!{StateTests_RandomTests_st201503200841JS, "StateTests/RandomTests/st201503200841JS"}
declare_test!{StateTests_RandomTests_st201503200848JS, "StateTests/RandomTests/st201503200848JS"}
declare_test!{StateTests_RandomTests_st201503240609JS, "StateTests/RandomTests/st201503240609JS"}
declare_test!{StateTests_RandomTests_st201503302200JS, "StateTests/RandomTests/st201503302200JS"}
declare_test!{StateTests_RandomTests_st201503302202JS, "StateTests/RandomTests/st201503302202JS"}
declare_test!{StateTests_RandomTests_st201503302206JS, "StateTests/RandomTests/st201503302206JS"}
declare_test!{StateTests_RandomTests_st201503302208JS, "StateTests/RandomTests/st201503302208JS"}
declare_test!{StateTests_RandomTests_st201503302210JS, "StateTests/RandomTests/st201503302210JS"}
declare_test!{StateTests_RandomTests_st201503302211JS, "StateTests/RandomTests/st201503302211JS"}
declare_test!{StateTests_RandomTests_st201504011535GO, "StateTests/RandomTests/st201504011535GO"}
declare_test!{StateTests_RandomTests_st201504011536GO, "StateTests/RandomTests/st201504011536GO"}
declare_test!{StateTests_RandomTests_st201504011547GO, "StateTests/RandomTests/st201504011547GO"}
declare_test!{StateTests_RandomTests_st201504011916JS, "StateTests/RandomTests/st201504011916JS"}
declare_test!{StateTests_RandomTests_st201504012130JS, "StateTests/RandomTests/st201504012130JS"}
declare_test!{StateTests_RandomTests_st201504012259JS, "StateTests/RandomTests/st201504012259JS"}
declare_test!{StateTests_RandomTests_st201504012359JS, "StateTests/RandomTests/st201504012359JS"}
declare_test!{StateTests_RandomTests_st201504020305JS, "StateTests/RandomTests/st201504020305JS"}
declare_test!{StateTests_RandomTests_st201504020400JS, "StateTests/RandomTests/st201504020400JS"}
declare_test!{StateTests_RandomTests_st201504020428JS, "StateTests/RandomTests/st201504020428JS"}
declare_test!{StateTests_RandomTests_st201504020431JS, "StateTests/RandomTests/st201504020431JS"}
declare_test!{StateTests_RandomTests_st201504020444JS, "StateTests/RandomTests/st201504020444JS"}
declare_test!{StateTests_RandomTests_st201504020538JS, "StateTests/RandomTests/st201504020538JS"}
declare_test!{StateTests_RandomTests_st201504020639JS, "StateTests/RandomTests/st201504020639JS"}
declare_test!{StateTests_RandomTests_st201504020836JS, "StateTests/RandomTests/st201504020836JS"}
declare_test!{StateTests_RandomTests_st201504020910JS, "StateTests/RandomTests/st201504020910JS"}
declare_test!{StateTests_RandomTests_st201504021057JS, "StateTests/RandomTests/st201504021057JS"}
declare_test!{StateTests_RandomTests_st201504021104JS, "StateTests/RandomTests/st201504021104JS"}
declare_test!{StateTests_RandomTests_st201504021237CPPJIT, "StateTests/RandomTests/st201504021237CPPJIT"}
declare_test!{StateTests_RandomTests_st201504021237GO, "StateTests/RandomTests/st201504021237GO"}
declare_test!{StateTests_RandomTests_st201504021237JS, "StateTests/RandomTests/st201504021237JS"}
declare_test!{StateTests_RandomTests_st201504021237PYTHON, "StateTests/RandomTests/st201504021237PYTHON"}
declare_test!{StateTests_RandomTests_st201504021949JS, "StateTests/RandomTests/st201504021949JS"}
declare_test!{StateTests_RandomTests_st201504022003CPPJIT, "StateTests/RandomTests/st201504022003CPPJIT"}
declare_test!{StateTests_RandomTests_st201504022124JS, "StateTests/RandomTests/st201504022124JS"}
declare_test!{StateTests_RandomTests_st201504030138JS, "StateTests/RandomTests/st201504030138JS"}
declare_test!{StateTests_RandomTests_st201504030646JS, "StateTests/RandomTests/st201504030646JS"}
declare_test!{StateTests_RandomTests_st201504030709JS, "StateTests/RandomTests/st201504030709JS"}
declare_test!{StateTests_RandomTests_st201504031133JS, "StateTests/RandomTests/st201504031133JS"}
declare_test!{StateTests_RandomTests_st201504031446JS, "StateTests/RandomTests/st201504031446JS"}
declare_test!{StateTests_RandomTests_st201504031841JS, "StateTests/RandomTests/st201504031841JS"}
declare_test!{StateTests_RandomTests_st201504041605JS, "StateTests/RandomTests/st201504041605JS"}
declare_test!{StateTests_RandomTests_st201504042052JS, "StateTests/RandomTests/st201504042052JS"}
declare_test!{StateTests_RandomTests_st201504042226CPPJIT, "StateTests/RandomTests/st201504042226CPPJIT"}
declare_test!{StateTests_RandomTests_st201504042355CPPJIT, "StateTests/RandomTests/st201504042355CPPJIT"}
declare_test!{StateTests_RandomTests_st201504050059JS, "StateTests/RandomTests/st201504050059JS"}
declare_test!{StateTests_RandomTests_st201504050733JS, "StateTests/RandomTests/st201504050733JS"}
declare_test!{StateTests_RandomTests_st201504051540JS, "StateTests/RandomTests/st201504051540JS"}
declare_test!{StateTests_RandomTests_st201504051944CPPJIT, "StateTests/RandomTests/st201504051944CPPJIT"}
declare_test!{StateTests_RandomTests_st201504052008CPPJIT, "StateTests/RandomTests/st201504052008CPPJIT"}
declare_test!{StateTests_RandomTests_st201504052014GO, "StateTests/RandomTests/st201504052014GO"}
declare_test!{StateTests_RandomTests_st201504052031CPPJIT, "StateTests/RandomTests/st201504052031CPPJIT"}
declare_test!{StateTests_RandomTests_st201504060057CPPJIT, "StateTests/RandomTests/st201504060057CPPJIT"}
declare_test!{StateTests_RandomTests_st201504060418CPPJIT, "StateTests/RandomTests/st201504060418CPPJIT"}
declare_test!{StateTests_RandomTests_st201504061106CPPJIT, "StateTests/RandomTests/st201504061106CPPJIT"}
declare_test!{StateTests_RandomTests_st201504061134CPPJIT, "StateTests/RandomTests/st201504061134CPPJIT"}
declare_test!{StateTests_RandomTests_st201504062033CPPJIT, "StateTests/RandomTests/st201504062033CPPJIT"}
declare_test!{StateTests_RandomTests_st201504062046CPPJIT, "StateTests/RandomTests/st201504062046CPPJIT"}
declare_test!{StateTests_RandomTests_st201504062314CPPJIT, "StateTests/RandomTests/st201504062314CPPJIT"}
declare_test!{StateTests_RandomTests_st201504070746JS, "StateTests/RandomTests/st201504070746JS"}
declare_test!{StateTests_RandomTests_st201504070816CPPJIT, "StateTests/RandomTests/st201504070816CPPJIT"}
declare_test!{StateTests_RandomTests_st201504070836CPPJIT, "StateTests/RandomTests/st201504070836CPPJIT"}
declare_test!{StateTests_RandomTests_st201504070839CPPJIT, "StateTests/RandomTests/st201504070839CPPJIT"}
declare_test!{StateTests_RandomTests_st201504071041CPPJIT, "StateTests/RandomTests/st201504071041CPPJIT"}
declare_test!{StateTests_RandomTests_st201504071056CPPJIT, "StateTests/RandomTests/st201504071056CPPJIT"}
declare_test!{StateTests_RandomTests_st201504071621CPPJIT, "StateTests/RandomTests/st201504071621CPPJIT"}
declare_test!{StateTests_RandomTests_st201504071653CPPJIT, "StateTests/RandomTests/st201504071653CPPJIT"}
declare_test!{StateTests_RandomTests_st201504071750CPPJIT, "StateTests/RandomTests/st201504071750CPPJIT"}
declare_test!{StateTests_RandomTests_st201504071905CPPJIT, "StateTests/RandomTests/st201504071905CPPJIT"}
declare_test!{StateTests_RandomTests_st201504080454CPPJIT, "StateTests/RandomTests/st201504080454CPPJIT"}
declare_test!{StateTests_RandomTests_st201504080457CPPJIT, "StateTests/RandomTests/st201504080457CPPJIT"}
declare_test!{StateTests_RandomTests_st201504080650CPPJIT, "StateTests/RandomTests/st201504080650CPPJIT"}
declare_test!{StateTests_RandomTests_st201504080840CPPJIT, "StateTests/RandomTests/st201504080840CPPJIT"}
declare_test!{StateTests_RandomTests_st201504080948CPPJIT, "StateTests/RandomTests/st201504080948CPPJIT"}
declare_test!{StateTests_RandomTests_st201504081100CPPJIT, "StateTests/RandomTests/st201504081100CPPJIT"}
declare_test!{StateTests_RandomTests_st201504081134CPPJIT, "StateTests/RandomTests/st201504081134CPPJIT"}
declare_test!{StateTests_RandomTests_st201504081138CPPJIT, "StateTests/RandomTests/st201504081138CPPJIT"}
declare_test!{StateTests_RandomTests_st201504081611CPPJIT, "StateTests/RandomTests/st201504081611CPPJIT"}
declare_test!{StateTests_RandomTests_st201504081841JAVA, "StateTests/RandomTests/st201504081841JAVA"}
declare_test!{StateTests_RandomTests_st201504081842JAVA, "StateTests/RandomTests/st201504081842JAVA"}
declare_test!{StateTests_RandomTests_st201504081843JAVA, "StateTests/RandomTests/st201504081843JAVA"}
declare_test!{StateTests_RandomTests_st201504081928CPPJIT, "StateTests/RandomTests/st201504081928CPPJIT"}
declare_test!{StateTests_RandomTests_st201504081953JAVA, "StateTests/RandomTests/st201504081953JAVA"}
declare_test!{StateTests_RandomTests_st201504081954JAVA, "StateTests/RandomTests/st201504081954JAVA"}
declare_test!{StateTests_RandomTests_st201504081955JAVA, "StateTests/RandomTests/st201504081955JAVA"}
declare_test!{StateTests_RandomTests_st201504081956JAVA, "StateTests/RandomTests/st201504081956JAVA"}
declare_test!{StateTests_RandomTests_st201504081957JAVA, "StateTests/RandomTests/st201504081957JAVA"}
declare_test!{StateTests_RandomTests_st201504082000JAVA, "StateTests/RandomTests/st201504082000JAVA"}
declare_test!{StateTests_RandomTests_st201504082001JAVA, "StateTests/RandomTests/st201504082001JAVA"}
declare_test!{StateTests_RandomTests_st201504082002JAVA, "StateTests/RandomTests/st201504082002JAVA"}
declare_test!{StateTests_RandomTests_st201504090553CPPJIT, "StateTests/RandomTests/st201504090553CPPJIT"}
declare_test!{StateTests_RandomTests_st201504090657CPPJIT, "StateTests/RandomTests/st201504090657CPPJIT"}
declare_test!{StateTests_RandomTests_st201504091403CPPJIT, "StateTests/RandomTests/st201504091403CPPJIT"}
declare_test!{StateTests_RandomTests_st201504091641CPPJIT, "StateTests/RandomTests/st201504091641CPPJIT"}
declare_test!{StateTests_RandomTests_st201504092303CPPJIT, "StateTests/RandomTests/st201504092303CPPJIT"}
declare_test!{StateTests_RandomTests_st201504100125CPPJIT, "StateTests/RandomTests/st201504100125CPPJIT"}
declare_test!{StateTests_RandomTests_st201504100215CPPJIT, "StateTests/RandomTests/st201504100215CPPJIT"}
declare_test!{StateTests_RandomTests_st201504100226PYTHON, "StateTests/RandomTests/st201504100226PYTHON"}
declare_test!{StateTests_RandomTests_st201504100308CPPJIT, "StateTests/RandomTests/st201504100308CPPJIT"}
declare_test!{StateTests_RandomTests_st201504100337CPPJIT, "StateTests/RandomTests/st201504100337CPPJIT"}
declare_test!{StateTests_RandomTests_st201504100341CPPJIT, "StateTests/RandomTests/st201504100341CPPJIT"}
declare_test!{StateTests_RandomTests_st201504101009CPPJIT, "StateTests/RandomTests/st201504101009CPPJIT"}
declare_test!{StateTests_RandomTests_st201504101150CPPJIT, "StateTests/RandomTests/st201504101150CPPJIT"}
declare_test!{StateTests_RandomTests_st201504101223CPPJIT, "StateTests/RandomTests/st201504101223CPPJIT"}
declare_test!{StateTests_RandomTests_st201504101338CPPJIT, "StateTests/RandomTests/st201504101338CPPJIT"}
declare_test!{StateTests_RandomTests_st201504101754PYTHON, "StateTests/RandomTests/st201504101754PYTHON"}
declare_test!{StateTests_RandomTests_st201504111554CPPJIT, "StateTests/RandomTests/st201504111554CPPJIT"}
declare_test!{StateTests_RandomTests_st201504130653JS, "StateTests/RandomTests/st201504130653JS"}
declare_test!{StateTests_RandomTests_st201504131821CPPJIT, "StateTests/RandomTests/st201504131821CPPJIT"}
declare_test!{StateTests_RandomTests_st201504140229CPPJIT, "StateTests/RandomTests/st201504140229CPPJIT"}
declare_test!{StateTests_RandomTests_st201504140236CPPJIT, "StateTests/RandomTests/st201504140236CPPJIT"}
declare_test!{StateTests_RandomTests_st201504140359CPPJIT, "StateTests/RandomTests/st201504140359CPPJIT"}
declare_test!{StateTests_RandomTests_st201504140750CPPJIT, "StateTests/RandomTests/st201504140750CPPJIT"}
declare_test!{StateTests_RandomTests_st201504140818CPPJIT, "StateTests/RandomTests/st201504140818CPPJIT"}
declare_test!{StateTests_RandomTests_st201504140900CPPJIT, "StateTests/RandomTests/st201504140900CPPJIT"}
declare_test!{StateTests_RandomTests_st201504150854CPPJIT, "StateTests/RandomTests/st201504150854CPPJIT"}
declare_test!{StateTests_RandomTests_st201504151057CPPJIT, "StateTests/RandomTests/st201504151057CPPJIT"}
declare_test!{StateTests_RandomTests_st201504202124CPPJIT, "StateTests/RandomTests/st201504202124CPPJIT"}
declare_test!{StateTests_RandomTests_st201504210245CPPJIT, "StateTests/RandomTests/st201504210245CPPJIT"}
declare_test!{StateTests_RandomTests_st201504210957CPPJIT, "StateTests/RandomTests/st201504210957CPPJIT"}
declare_test!{StateTests_RandomTests_st201504211739CPPJIT, "StateTests/RandomTests/st201504211739CPPJIT"}
declare_test!{StateTests_RandomTests_st201504212038CPPJIT, "StateTests/RandomTests/st201504212038CPPJIT"}
declare_test!{StateTests_RandomTests_st201504230729CPPJIT, "StateTests/RandomTests/st201504230729CPPJIT"}
declare_test!{StateTests_RandomTests_st201504231639CPPJIT, "StateTests/RandomTests/st201504231639CPPJIT"}
declare_test!{StateTests_RandomTests_st201504231710CPPJIT, "StateTests/RandomTests/st201504231710CPPJIT"}
declare_test!{StateTests_RandomTests_st201504231742CPPJIT, "StateTests/RandomTests/st201504231742CPPJIT"}
declare_test!{StateTests_RandomTests_st201504232350CPPJIT, "StateTests/RandomTests/st201504232350CPPJIT"}
declare_test!{StateTests_RandomTests_st201504240140CPPJIT, "StateTests/RandomTests/st201504240140CPPJIT"}
declare_test!{StateTests_RandomTests_st201504240220CPPJIT, "StateTests/RandomTests/st201504240220CPPJIT"}
declare_test!{StateTests_RandomTests_st201504240351CPPJIT, "StateTests/RandomTests/st201504240351CPPJIT"}
declare_test!{StateTests_RandomTests_st201504240817CPPJIT, "StateTests/RandomTests/st201504240817CPPJIT"}
declare_test!{StateTests_RandomTests_st201504241118CPPJIT, "StateTests/RandomTests/st201504241118CPPJIT"}
declare_test!{StateTests_RandomTests_st201505021810CPPJIT, "StateTests/RandomTests/st201505021810CPPJIT"}
declare_test!{StateTests_RandomTests_st201505050557JS, "StateTests/RandomTests/st201505050557JS"}
declare_test!{StateTests_RandomTests_st201505050929GO, "StateTests/RandomTests/st201505050929GO"}
declare_test!{StateTests_RandomTests_st201505050942PYTHON, "StateTests/RandomTests/st201505050942PYTHON"}
declare_test!{StateTests_RandomTests_st201505051004PYTHON, "StateTests/RandomTests/st201505051004PYTHON"}
declare_test!{StateTests_RandomTests_st201505051016PYTHON, "StateTests/RandomTests/st201505051016PYTHON"}
declare_test!{StateTests_RandomTests_st201505051114GO, "StateTests/RandomTests/st201505051114GO"}
declare_test!{StateTests_RandomTests_st201505051238GO, "StateTests/RandomTests/st201505051238GO"}
declare_test!{StateTests_RandomTests_st201505051249GO, "StateTests/RandomTests/st201505051249GO"}
declare_test!{StateTests_RandomTests_st201505051558PYTHON, "StateTests/RandomTests/st201505051558PYTHON"}
declare_test!{StateTests_RandomTests_st201505051611PYTHON, "StateTests/RandomTests/st201505051611PYTHON"}
declare_test!{StateTests_RandomTests_st201505051648JS, "StateTests/RandomTests/st201505051648JS"}
declare_test!{StateTests_RandomTests_st201505051710GO, "StateTests/RandomTests/st201505051710GO"}
declare_test!{StateTests_RandomTests_st201505052013GO, "StateTests/RandomTests/st201505052013GO"}
declare_test!{StateTests_RandomTests_st201505052102JS, "StateTests/RandomTests/st201505052102JS"}
declare_test!{StateTests_RandomTests_st201505052235GO, "StateTests/RandomTests/st201505052235GO"}
declare_test!{StateTests_RandomTests_st201505052238JS, "StateTests/RandomTests/st201505052238JS"}
declare_test!{StateTests_RandomTests_st201505052242PYTHON, "StateTests/RandomTests/st201505052242PYTHON"}
declare_test!{StateTests_RandomTests_st201505052343PYTHON, "StateTests/RandomTests/st201505052343PYTHON"}
declare_test!{StateTests_RandomTests_st201505060120GO, "StateTests/RandomTests/st201505060120GO"}
declare_test!{StateTests_RandomTests_st201505060121GO, "StateTests/RandomTests/st201505060121GO"}
declare_test!{StateTests_RandomTests_st201505060136PYTHON, "StateTests/RandomTests/st201505060136PYTHON"}
declare_test!{StateTests_RandomTests_st201505060646JS, "StateTests/RandomTests/st201505060646JS"}
declare_test!{StateTests_RandomTests_st201505252314CPPJIT, "StateTests/RandomTests/st201505252314CPPJIT"}
declare_test!{StateTests_RandomTests_st201505272131CPPJIT, "StateTests/RandomTests/st201505272131CPPJIT"}
declare_test!{StateTests_RandomTests_st201506040034GO, "StateTests/RandomTests/st201506040034GO"}
declare_test!{StateTests_RandomTests_st201506040157GO, "StateTests/RandomTests/st201506040157GO"}
declare_test!{StateTests_RandomTests_st201506052130GO, "StateTests/RandomTests/st201506052130GO"}
declare_test!{StateTests_RandomTests_st201506060929GO, "StateTests/RandomTests/st201506060929GO"}
declare_test!{StateTests_RandomTests_st201506061255GO, "StateTests/RandomTests/st201506061255GO"}
declare_test!{StateTests_RandomTests_st201506062331GO, "StateTests/RandomTests/st201506062331GO"}
declare_test!{StateTests_RandomTests_st201506070548GO, "StateTests/RandomTests/st201506070548GO"}
declare_test!{StateTests_RandomTests_st201506071050GO, "StateTests/RandomTests/st201506071050GO"}
declare_test!{StateTests_RandomTests_st201506071624GO, "StateTests/RandomTests/st201506071624GO"}
declare_test!{StateTests_RandomTests_st201506071819GO, "StateTests/RandomTests/st201506071819GO"}
declare_test!{StateTests_RandomTests_st201506072007GO, "StateTests/RandomTests/st201506072007GO"}
declare_test!{StateTests_RandomTests_st201506080556GO, "StateTests/RandomTests/st201506080556GO"}
declare_test!{StateTests_RandomTests_st201506080721GO, "StateTests/RandomTests/st201506080721GO"}
declare_test!{StateTests_RandomTests_st201506091836GO, "StateTests/RandomTests/st201506091836GO"}
declare_test!{StateTests_RandomTests_st201506092032GO, "StateTests/RandomTests/st201506092032GO"}
declare_test!{StateTests_RandomTests_st201506101359JS, "StateTests/RandomTests/st201506101359JS"}
declare_test!{StateTests_RandomTests_st201507030359GO, "StateTests/RandomTests/st201507030359GO"}
} }

View File

@ -15,21 +15,63 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
pub use util::*; pub use util::*;
use std::fs::{File, read_dir};
use std::path::Path;
use std::ffi::OsString;
pub fn run_test_path(p: &Path, skip: &[&'static str], runner: fn (json_data: &[u8]) -> Vec<String>) {
let path = Path::new(p);
let s: HashSet<OsString> = skip.iter().map(|s| {
let mut os: OsString = s.into();
os.push(".json");
os
}).collect();
if path.is_dir() {
for p in read_dir(path).unwrap().filter_map(|e| {
let e = e.unwrap();
if s.contains(&e.file_name()) {
None
} else {
Some(e.path())
}}) {
run_test_path(&p, skip, runner)
}
} else {
let mut path = p.to_path_buf();
path.set_extension("json");
run_test_file(&path, runner)
}
}
pub fn run_test_file(path: &Path, runner: fn (json_data: &[u8]) -> Vec<String>) {
let mut data = Vec::new();
let mut file = File::open(&path).expect("Error opening test file");
file.read_to_end(&mut data).expect("Error reading test file");
let results = runner(&data);
assert!(results.is_empty());
}
macro_rules! test { macro_rules! test {
($name: expr) => { ($name: expr, $skip: expr) => {
assert!(do_json_test(include_bytes!(concat!("../../res/ethereum/tests/", $name, ".json"))).is_empty()); ::json_tests::test_common::run_test_path(::std::path::Path::new(concat!("res/ethereum/tests/", $name)), &$skip, do_json_test);
} }
} }
#[macro_export] #[macro_export]
macro_rules! declare_test { macro_rules! declare_test {
(skip => $arr: expr, $id: ident, $name: expr) => {
#[test]
#[allow(non_snake_case)]
fn $id() {
test!($name, $arr);
}
};
(ignore => $id: ident, $name: expr) => { (ignore => $id: ident, $name: expr) => {
#[ignore] #[ignore]
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn $id() { fn $id() {
test!($name); test!($name, []);
} }
}; };
(heavy => $id: ident, $name: expr) => { (heavy => $id: ident, $name: expr) => {
@ -37,14 +79,14 @@ macro_rules! declare_test {
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn $id() { fn $id() {
test!($name); test!($name, []);
} }
}; };
($id: ident, $name: expr) => { ($id: ident, $name: expr) => {
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn $id() { fn $id() {
test!($name); test!($name, []);
} }
} }
} }

View File

@ -42,7 +42,7 @@ pub enum ChainEra {
Frontier, Frontier,
Homestead, Homestead,
Eip150, Eip150,
Eip161, _Eip161,
TransitionTest, TransitionTest,
} }
@ -359,12 +359,23 @@ pub fn get_temp_state() -> GuardedTempResult<State<::state_db::StateDB>> {
} }
} }
pub fn get_temp_mem_state() -> State<::state_db::StateDB> {
let journal_db = get_temp_mem_state_db();
State::new(journal_db, U256::from(0), Default::default())
}
pub fn get_temp_state_db_in(path: &Path) -> StateDB { pub fn get_temp_state_db_in(path: &Path) -> StateDB {
let db = new_db(path.to_str().expect("Only valid utf8 paths for tests.")); let db = new_db(path.to_str().expect("Only valid utf8 paths for tests."));
let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, ::db::COL_STATE);
StateDB::new(journal_db, 5 * 1024 * 1024) StateDB::new(journal_db, 5 * 1024 * 1024)
} }
pub fn get_temp_mem_state_db() -> StateDB {
let db = Arc::new(::util::kvdb::in_memory(::db::NUM_COLUMNS.unwrap_or(0)));
let journal_db = journaldb::new(db, journaldb::Algorithm::EarlyMerge, ::db::COL_STATE);
StateDB::new(journal_db, 5 * 1024 * 1024)
}
pub fn get_temp_state_in(path: &Path) -> State<::state_db::StateDB> { pub fn get_temp_state_in(path: &Path) -> State<::state_db::StateDB> {
let journal_db = get_temp_state_db_in(path); let journal_db = get_temp_state_db_in(path);
State::new(journal_db, U256::from(0), Default::default()) State::new(journal_db, U256::from(0), Default::default())

View File

@ -94,11 +94,11 @@ pub trait Keccak256<T> {
fn keccak256(&self) -> T where T: Sized; fn keccak256(&self) -> T where T: Sized;
} }
impl Keccak256<[u8; 32]> for [u8] { impl<T> Keccak256<[u8; 32]> for T where T: AsRef<[u8]> {
fn keccak256(&self) -> [u8; 32] { fn keccak256(&self) -> [u8; 32] {
let mut keccak = Keccak::new_keccak256(); let mut keccak = Keccak::new_keccak256();
let mut result = [0u8; 32]; let mut result = [0u8; 32];
keccak.update(self); keccak.update(self.as_ref());
keccak.finalize(&mut result); keccak.finalize(&mut result);
result result
} }

View File

@ -19,10 +19,10 @@ time = "0.1.34"
itertools = "0.5" itertools = "0.5"
parking_lot = "0.4" parking_lot = "0.4"
ethcrypto = { path = "../ethcrypto" } ethcrypto = { path = "../ethcrypto" }
ethcore-util = { path = "../util" } ethcore-bigint = { path = "../util/bigint" }
smallvec = "0.3.1" smallvec = "0.3.1"
ethcore-devtools = { path = "../devtools" }
parity-wordlist = "1.0" parity-wordlist = "1.0"
tempdir = "0.3"
[features] [features]
cli = ["docopt"] cli = ["docopt"]

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::iter::repeat; use std::iter::repeat;
use std::str;
use ethkey::Secret; use ethkey::Secret;
use {json, Error, crypto}; use {json, Error, crypto};
use crypto::Keccak256; use crypto::Keccak256;
@ -46,22 +47,38 @@ impl From<json::Crypto> for Crypto {
} }
} }
impl Into<json::Crypto> for Crypto { impl From<Crypto> for json::Crypto {
fn into(self) -> json::Crypto { fn from(c: Crypto) -> Self {
json::Crypto { json::Crypto {
cipher: self.cipher.into(), cipher: c.cipher.into(),
ciphertext: self.ciphertext.into(), ciphertext: c.ciphertext.into(),
kdf: self.kdf.into(), kdf: c.kdf.into(),
mac: self.mac.into(), mac: c.mac.into(),
} }
} }
} }
impl str::FromStr for Crypto {
type Err = <json::Crypto as str::FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<json::Crypto>().map(Into::into)
}
}
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
json::Crypto::from(c).into()
}
}
impl Crypto { impl Crypto {
/// Encrypt account secret
pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self { pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self {
Crypto::with_plain(&*secret, password, iterations) Crypto::with_plain(&*secret, password, iterations)
} }
/// Encrypt custom plain data
pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Self { pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Self {
let salt: [u8; 32] = Random::random(); let salt: [u8; 32] = Random::random();
let iv: [u8; 16] = Random::random(); let iv: [u8; 16] = Random::random();
@ -98,6 +115,7 @@ impl Crypto {
} }
} }
/// Try to decrypt and convert result to account secret
pub fn secret(&self, password: &str) -> Result<Secret, Error> { pub fn secret(&self, password: &str) -> Result<Secret, Error> {
if self.ciphertext.len() > 32 { if self.ciphertext.len() > 32 {
return Err(Error::InvalidSecret); return Err(Error::InvalidSecret);
@ -107,6 +125,7 @@ impl Crypto {
Ok(Secret::from_slice(&secret)?) Ok(Secret::from_slice(&secret)?)
} }
/// Try to decrypt and return result as is
pub fn decrypt(&self, password: &str) -> Result<Vec<u8>, Error> { pub fn decrypt(&self, password: &str) -> Result<Vec<u8>, Error> {
let expected_len = self.ciphertext.len(); let expected_len = self.ciphertext.len();
self.do_decrypt(password, expected_len) self.do_decrypt(password, expected_len)

View File

@ -225,8 +225,8 @@ impl<T> KeyDirectory for DiskDirectory<T> where T: KeyFileManager {
Some(self) Some(self)
} }
fn unique_repr(&self) -> Result<u64, Error> { fn unique_repr(&self) -> Result<u64, Error> {
self.files_hash() self.files_hash()
} }
} }
@ -280,12 +280,14 @@ impl KeyFileManager for DiskKeyFileManager {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
extern crate tempdir;
use std::{env, fs}; use std::{env, fs};
use super::RootDiskDirectory; use super::RootDiskDirectory;
use dir::{KeyDirectory, VaultKey}; use dir::{KeyDirectory, VaultKey};
use account::SafeAccount; use account::SafeAccount;
use ethkey::{Random, Generator}; use ethkey::{Random, Generator};
use devtools::RandomTempPath; use self::tempdir::TempDir;
#[test] #[test]
fn should_create_new_account() { fn should_create_new_account() {
@ -344,7 +346,7 @@ mod test {
#[test] #[test]
fn should_list_vaults() { fn should_list_vaults() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let directory = RootDiskDirectory::create(&temp_path).unwrap(); let directory = RootDiskDirectory::create(&temp_path).unwrap();
let vault_provider = directory.as_vault_provider().unwrap(); let vault_provider = directory.as_vault_provider().unwrap();
vault_provider.create("vault1", VaultKey::new("password1", 1)).unwrap(); vault_provider.create("vault1", VaultKey::new("password1", 1)).unwrap();
@ -359,11 +361,11 @@ mod test {
#[test] #[test]
fn hash_of_files() { fn hash_of_files() {
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let directory = RootDiskDirectory::create(&temp_path).unwrap(); let directory = RootDiskDirectory::create(&temp_path).unwrap();
let hash = directory.files_hash().expect("Files hash should be calculated ok"); let hash = directory.files_hash().expect("Files hash should be calculated ok");
assert_eq!( assert_eq!(
hash, hash,
15130871412783076140 15130871412783076140
); );
@ -373,7 +375,7 @@ mod test {
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
directory.insert(account).expect("Account should be inserted ok"); directory.insert(account).expect("Account should be inserted ok");
let new_hash = directory.files_hash().expect("New files hash should be calculated ok"); let new_hash = directory.files_hash().expect("New files hash should be calculated ok");
assert!(new_hash != hash, "hash of the file list should change once directory content changed"); assert!(new_hash != hash, "hash of the file list should change once directory content changed");
} }

View File

@ -18,7 +18,7 @@ use std::{fs, io};
use std::path::{PathBuf, Path}; use std::path::{PathBuf, Path};
use parking_lot::Mutex; use parking_lot::Mutex;
use {json, SafeAccount, Error}; use {json, SafeAccount, Error};
use util::sha3::Hashable; use crypto::Keccak256;
use super::super::account::Crypto; use super::super::account::Crypto;
use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError}; use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
use super::disk::{DiskDirectory, KeyFileManager}; use super::disk::{DiskDirectory, KeyFileManager};
@ -234,7 +234,7 @@ fn check_vault_name(name: &str) -> bool {
/// Vault can be empty, but still must be pluggable => we store vault password in separate file /// Vault can be empty, but still must be pluggable => we store vault password in separate file
fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> { fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> {
let password_hash = key.password.sha3(); let password_hash = key.password.keccak256();
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations); let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations);
let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into(); let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
@ -268,8 +268,8 @@ fn read_vault_file<P>(vault_dir_path: P, key: Option<&VaultKey>) -> Result<Strin
if let Some(key) = key { if let Some(key) = key {
let password_bytes = vault_file_crypto.decrypt(&key.password)?; let password_bytes = vault_file_crypto.decrypt(&key.password)?;
let password_hash = key.password.sha3(); let password_hash = key.password.keccak256();
if &*password_hash != password_bytes.as_slice() { if password_hash != password_bytes.as_slice() {
return Err(Error::InvalidPassword); return Err(Error::InvalidPassword);
} }
} }
@ -279,12 +279,14 @@ fn read_vault_file<P>(vault_dir_path: P, key: Option<&VaultKey>) -> Result<Strin
#[cfg(test)] #[cfg(test)]
mod test { mod test {
extern crate tempdir;
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use dir::VaultKey; use dir::VaultKey;
use super::{VAULT_FILE_NAME, check_vault_name, make_vault_dir_path, create_vault_file, read_vault_file, VaultDiskDirectory}; use super::{VAULT_FILE_NAME, check_vault_name, make_vault_dir_path, create_vault_file, read_vault_file, VaultDiskDirectory};
use devtools::RandomTempPath; use self::tempdir::TempDir;
#[test] #[test]
fn check_vault_name_succeeds() { fn check_vault_name_succeeds() {
@ -320,9 +322,9 @@ mod test {
#[test] #[test]
fn create_vault_file_succeeds() { fn create_vault_file_succeeds() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let mut vault_dir: PathBuf = temp_path.as_path().into(); let mut vault_dir: PathBuf = temp_path.path().into();
vault_dir.push("vault"); vault_dir.push("vault");
fs::create_dir_all(&vault_dir).unwrap(); fs::create_dir_all(&vault_dir).unwrap();
@ -339,10 +341,10 @@ mod test {
#[test] #[test]
fn read_vault_file_succeeds() { fn read_vault_file_succeeds() {
// given // given
let temp_path = RandomTempPath::create_dir(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"758696c8dc6378ab9b25bb42790da2f5"},"ciphertext":"54eb50683717d41caaeb12ea969f2c159daada5907383f26f327606a37dc7168","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"3c320fa566a1a7963ac8df68a19548d27c8f40bf92ef87c84594dcd5bbc402b6"},"mac":"9e5c2314c2a0781962db85611417c614bd6756666b6b1e93840f5b6ed895f003"}}"#; let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"758696c8dc6378ab9b25bb42790da2f5"},"ciphertext":"54eb50683717d41caaeb12ea969f2c159daada5907383f26f327606a37dc7168","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"3c320fa566a1a7963ac8df68a19548d27c8f40bf92ef87c84594dcd5bbc402b6"},"mac":"9e5c2314c2a0781962db85611417c614bd6756666b6b1e93840f5b6ed895f003"}}"#;
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
let mut vault_file_path: PathBuf = dir.clone(); let mut vault_file_path: PathBuf = dir.clone();
vault_file_path.push(VAULT_FILE_NAME); vault_file_path.push(VAULT_FILE_NAME);
{ {
@ -360,9 +362,9 @@ mod test {
#[test] #[test]
fn read_vault_file_fails() { fn read_vault_file_fails() {
// given // given
let temp_path = RandomTempPath::create_dir(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password1", 1024); let key = VaultKey::new("password1", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
let mut vault_file_path: PathBuf = dir.clone(); let mut vault_file_path: PathBuf = dir.clone();
vault_file_path.push(VAULT_FILE_NAME); vault_file_path.push(VAULT_FILE_NAME);
@ -389,9 +391,9 @@ mod test {
#[test] #[test]
fn vault_directory_can_be_created() { fn vault_directory_can_be_created() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
// when // when
let vault = VaultDiskDirectory::create(&dir, "vault", key.clone()); let vault = VaultDiskDirectory::create(&dir, "vault", key.clone());
@ -409,9 +411,9 @@ mod test {
#[test] #[test]
fn vault_directory_cannot_be_created_if_already_exists() { fn vault_directory_cannot_be_created_if_already_exists() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
let mut vault_dir = dir.clone(); let mut vault_dir = dir.clone();
vault_dir.push("vault"); vault_dir.push("vault");
fs::create_dir_all(&vault_dir).unwrap(); fs::create_dir_all(&vault_dir).unwrap();
@ -426,9 +428,9 @@ mod test {
#[test] #[test]
fn vault_directory_cannot_be_opened_if_not_exists() { fn vault_directory_cannot_be_opened_if_not_exists() {
// given // given
let temp_path = RandomTempPath::create_dir(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
// when // when
let vault = VaultDiskDirectory::at(&dir, "vault", key); let vault = VaultDiskDirectory::at(&dir, "vault", key);

View File

@ -620,13 +620,14 @@ impl SimpleSecretStore for EthMultiStore {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate tempdir;
use dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory}; use dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory};
use ethkey::{Random, Generator, KeyPair}; use ethkey::{Random, Generator, KeyPair};
use secret_store::{SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation}; use secret_store::{SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation};
use super::{EthStore, EthMultiStore}; use super::{EthStore, EthMultiStore};
use devtools::RandomTempPath; use self::tempdir::TempDir;
use util::H256; use bigint::hash::H256;
fn keypair() -> KeyPair { fn keypair() -> KeyPair {
Random.generate().unwrap() Random.generate().unwrap()
@ -642,13 +643,13 @@ mod tests {
struct RootDiskDirectoryGuard { struct RootDiskDirectoryGuard {
pub key_dir: Option<Box<KeyDirectory>>, pub key_dir: Option<Box<KeyDirectory>>,
_path: RandomTempPath, _path: TempDir,
} }
impl RootDiskDirectoryGuard { impl RootDiskDirectoryGuard {
pub fn new() -> Self { pub fn new() -> Self {
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let disk_dir = Box::new(RootDiskDirectory::create(temp_path.as_path()).unwrap()); let disk_dir = Box::new(RootDiskDirectory::create(temp_path.path()).unwrap());
RootDiskDirectoryGuard { RootDiskDirectoryGuard {
key_dir: Some(disk_dir), key_dir: Some(disk_dir),

View File

@ -14,10 +14,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::fmt; use std::{fmt, str};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use serde::de::{Visitor, MapVisitor, Error}; use serde::de::{Visitor, MapVisitor, Error};
use serde_json;
use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256, Bytes}; use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256, Bytes};
pub type CipherText = Bytes; pub type CipherText = Bytes;
@ -30,6 +31,20 @@ pub struct Crypto {
pub mac: H256, pub mac: H256,
} }
impl str::FromStr for Crypto {
type Err = serde_json::error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
serde_json::from_str(s)
}
}
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
serde_json::to_string(&c).expect("serialization cannot fail, cause all crypto keys are strings")
}
}
enum CryptoField { enum CryptoField {
Cipher, Cipher,
CipherParams, CipherParams,

View File

@ -29,9 +29,9 @@ extern crate serde_json;
extern crate smallvec; extern crate smallvec;
extern crate time; extern crate time;
extern crate tiny_keccak; extern crate tiny_keccak;
extern crate tempdir;
extern crate ethcore_devtools as devtools; extern crate ethcore_bigint as bigint;
extern crate ethcore_util as util;
extern crate ethcrypto as crypto; extern crate ethcrypto as crypto;
extern crate ethkey as _ethkey; extern crate ethkey as _ethkey;
extern crate parity_wordlist; extern crate parity_wordlist;
@ -54,7 +54,7 @@ mod presale;
mod random; mod random;
mod secret_store; mod secret_store;
pub use self::account::SafeAccount; pub use self::account::{SafeAccount, Crypto};
pub use self::error::Error; pub use self::error::Error;
pub use self::ethstore::{EthStore, EthMultiStore}; pub use self::ethstore::{EthStore, EthMultiStore};
pub use self::import::{import_accounts, read_geth_accounts}; pub use self::import::{import_accounts, read_geth_accounts};

View File

@ -19,7 +19,7 @@ use std::path::PathBuf;
use ethkey::{Address, Message, Signature, Secret, Public}; use ethkey::{Address, Message, Signature, Secret, Public};
use Error; use Error;
use json::{Uuid, OpaqueKeyFile}; use json::{Uuid, OpaqueKeyFile};
use util::H256; use bigint::hash::H256;
/// Key directory reference /// Key directory reference
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]

View File

@ -92,6 +92,7 @@ pub struct Client<F: Fetch + 'static = FetchClient> {
contract: URLHintContract, contract: URLHintContract,
fetch: F, fetch: F,
remote: Remote, remote: Remote,
random_path: Arc<Fn() -> PathBuf + Sync + Send>,
} }
impl Client { impl Client {
@ -109,6 +110,7 @@ impl<F: Fetch + 'static> Client<F> {
contract: URLHintContract::new(contract), contract: URLHintContract::new(contract),
fetch: fetch, fetch: fetch,
remote: remote, remote: remote,
random_path: Arc::new(random_temp_path),
} }
} }
} }
@ -131,6 +133,7 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
match url { match url {
Err(err) => on_done(Err(err)), Err(err) => on_done(Err(err)),
Ok(url) => { Ok(url) => {
let random_path = self.random_path.clone();
let future = self.fetch.fetch(&url).then(move |result| { let future = self.fetch.fetch(&url).then(move |result| {
fn validate_hash(path: PathBuf, hash: H256, result: Result<Response, FetchError>) -> Result<PathBuf, Error> { fn validate_hash(path: PathBuf, hash: H256, result: Result<Response, FetchError>) -> Result<PathBuf, Error> {
let response = result?; let response = result?;
@ -155,12 +158,12 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
} }
debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash); debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash);
let path = random_temp_path(); let path = random_path();
let res = validate_hash(path.clone(), hash, result); let res = validate_hash(path.clone(), hash, result);
if let Err(ref err) = res { if let Err(ref err) = res {
trace!(target: "fetch", "Error: {:?}", err); trace!(target: "fetch", "Error: {:?}", err);
// Remove temporary file in case of error // Remove temporary file in case of error
let _ = fs::remove_dir_all(&path); let _ = fs::remove_file(&path);
} }
on_done(res); on_done(res);
@ -192,7 +195,7 @@ mod tests {
use fetch::{self, Fetch}; use fetch::{self, Fetch};
use parity_reactor::Remote; use parity_reactor::Remote;
use urlhint::tests::{FakeRegistrar, URLHINT}; use urlhint::tests::{FakeRegistrar, URLHINT};
use super::{Error, Client, HashFetch}; use super::{Error, Client, HashFetch, random_temp_path};
#[derive(Clone)] #[derive(Clone)]
@ -262,12 +265,16 @@ mod tests {
let result = rx.recv().unwrap(); let result = rx.recv().unwrap();
assert_eq!(result.unwrap_err(), Error::InvalidStatus); assert_eq!(result.unwrap_err(), Error::InvalidStatus);
} }
#[test] #[test]
fn should_return_hash_mismatch() { fn should_return_hash_mismatch() {
// given // given
let registrar = Arc::new(registrar()); let registrar = Arc::new(registrar());
let fetch = FakeFetch { return_success: true }; let fetch = FakeFetch { return_success: true };
let client = Client::with_fetch(registrar.clone(), fetch, Remote::new_sync()); let mut client = Client::with_fetch(registrar.clone(), fetch, Remote::new_sync());
let path = random_temp_path();
let path2 = path.clone();
client.random_path = Arc::new(move || path2.clone());
// when // when
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
@ -279,6 +286,7 @@ mod tests {
let result = rx.recv().unwrap(); let result = rx.recv().unwrap();
let hash = "0x06b0a4f426f6713234b2d4b2468640bc4e0bb72657a920ad24c5087153c593c8".into(); let hash = "0x06b0a4f426f6713234b2d4b2468640bc4e0bb72657a920ad24c5087153c593c8".into();
assert_eq!(result.unwrap_err(), Error::HashMismatch { expected: 2.into(), got: hash }); assert_eq!(result.unwrap_err(), Error::HashMismatch { expected: 2.into(), got: hash });
assert!(!path.exists(), "Temporary file should be removed.");
} }
#[test] #[test]

View File

@ -1,6 +1,6 @@
{ {
"name": "parity.js", "name": "parity.js",
"version": "1.7.49", "version": "1.7.53",
"main": "release/index.js", "main": "release/index.js",
"jsnext:main": "src/index.js", "jsnext:main": "src/index.js",
"author": "Parity Team <admin@parity.io>", "author": "Parity Team <admin@parity.io>",

View File

@ -55,7 +55,7 @@ export default class Api extends EventEmitter {
.nodeKind() .nodeKind()
.then((nodeKind) => { .then((nodeKind) => {
if (nodeKind.availability === 'public') { if (nodeKind.availability === 'public') {
return new LocalAccountsMiddleware(transport); return LocalAccountsMiddleware;
} }
return null; return null;

View File

@ -1,19 +0,0 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default function () {
// empty file included while building parity.js (don't include local keygen)
}

View File

@ -18,8 +18,8 @@ import { randomPhrase } from '@parity/wordlist';
import { phraseToAddress, phraseToWallet } from './'; import { phraseToAddress, phraseToWallet } from './';
describe('api/local/ethkey', () => { describe('api/local/ethkey', () => {
describe.skip('phraseToAddress', function () { describe('phraseToAddress', function () {
this.timeout(10000); this.timeout(30000);
it('generates a valid address', () => { it('generates a valid address', () => {
const phrase = randomPhrase(12); const phrase = randomPhrase(12);
@ -37,8 +37,8 @@ describe('api/local/ethkey', () => {
}); });
}); });
describe.skip('phraseToWallet', function () { describe('phraseToWallet', function () {
this.timeout(10000); this.timeout(30000);
it('generates a valid wallet object', () => { it('generates a valid wallet object', () => {
const phrase = randomPhrase(12); const phrase = randomPhrase(12);

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import secp256k1 from 'secp256k1/js'; import secp256k1 from 'secp256k1';
import { keccak_256 as keccak256 } from 'js-sha3'; import { keccak_256 as keccak256 } from 'js-sha3';
import { bytesToHex } from '~/api/util/format'; import { bytesToHex } from '~/api/util/format';
@ -28,11 +28,9 @@ if (!isWorker) {
} }
// keythereum should never be used outside of the browser // keythereum should never be used outside of the browser
let keythereum = null; let keythereum = require('keythereum');
if (isWorker) { if (isWorker) {
require('keythereum/dist/keythereum');
keythereum = self.keythereum; keythereum = self.keythereum;
} }
@ -109,9 +107,13 @@ const actions = {
}; };
self.onmessage = function ({ data }) { self.onmessage = function ({ data }) {
const result = route(data); try {
const result = route(data);
postMessage(result); postMessage([null, result]);
} catch (err) {
postMessage([err, null]);
}
}; };
// Emulate a web worker in Node.js // Emulate a web worker in Node.js
@ -119,9 +121,13 @@ class KeyWorker {
postMessage (data) { postMessage (data) {
// Force async // Force async
setTimeout(() => { setTimeout(() => {
const result = route(data); try {
const result = route(data);
this.onmessage({ data: result }); this.onmessage({ data: [null, result] });
} catch (err) {
this.onmessage({ data: [err, null] });
}
}, 0); }, 0);
} }

View File

@ -33,8 +33,15 @@ class WorkerContainer {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this._worker.postMessage({ action, payload }); this._worker.postMessage({ action, payload });
this._worker.onmessage = ({ data }) => { this._worker.onmessage = ({ data }) => {
const [err, result] = data;
this.busy = false; this.busy = false;
resolve(data);
if (err) {
reject(err);
} else {
resolve(result);
}
}; };
}); });
} }

View File

@ -14,4 +14,4 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
export LocalAccountsMiddleware from './middleware'; export LocalAccountsMiddleware from './localAccountsMiddleware';

View File

@ -23,15 +23,6 @@ import { phraseToWallet, phraseToAddress, verifySecret } from './ethkey';
import { randomPhrase } from '@parity/wordlist'; import { randomPhrase } from '@parity/wordlist';
export default class LocalAccountsMiddleware extends Middleware { export default class LocalAccountsMiddleware extends Middleware {
// Maps transaction requests to transaction hashes.
// This allows the locally-signed transactions to emulate the signer.
transactionHashes = {};
transactions = {};
// Current transaction id. This doesn't need to be stored, as it's
// only relevant for the current the session.
transactionId = 1;
constructor (transport) { constructor (transport) {
super(transport); super(transport);
@ -170,13 +161,27 @@ export default class LocalAccountsMiddleware extends Middleware {
data data
} = Object.assign(transactions.get(id), modify); } = Object.assign(transactions.get(id), modify);
transactions.lock(id);
const account = accounts.get(from); const account = accounts.get(from);
return Promise.all([ return Promise.all([
this.rpcRequest('parity_nextNonce', [from]), this.rpcRequest('parity_nextNonce', [from]),
account.decryptPrivateKey(password) account.decryptPrivateKey(password)
]) ])
.catch((err) => {
transactions.unlock(id);
// transaction got unlocked, can propagate rejection further
throw err;
})
.then(([nonce, privateKey]) => { .then(([nonce, privateKey]) => {
if (!privateKey) {
transactions.unlock(id);
throw new Error('Invalid password');
}
const tx = new EthereumTx({ const tx = new EthereumTx({
nonce, nonce,
to, to,

View File

@ -0,0 +1,154 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import LocalAccountsMiddleware from './localAccountsMiddleware';
import JsonRpcBase from '../transport/jsonRpcBase';
const RPC_RESPONSE = Symbol('RPC response');
const ADDRESS = '0x00a329c0648769a73afac7f9381e08fb43dbea72';
const SECRET = '0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7';
const PASSWORD = 'password';
const FOO_PHRASE = 'foobar';
const FOO_PASSWORD = 'foopass';
const FOO_ADDRESS = '0x007ef7ac1058e5955e366ab9d6b6c4ebcc937e7e';
class MockedTransport extends JsonRpcBase {
_execute (method, params) {
return RPC_RESPONSE;
}
}
describe('api/local/LocalAccountsMiddleware', function () {
this.timeout(30000);
let transport;
beforeEach(() => {
transport = new MockedTransport();
transport.addMiddleware(LocalAccountsMiddleware);
// Same as `parity_newAccountFromPhrase` with empty phrase
return transport
.execute('parity_newAccountFromSecret', SECRET, PASSWORD)
.catch((_err) => {
// Ignore the error - all instances of LocalAccountsMiddleware
// share account storage
});
});
it('registers all necessary methods', () => {
return Promise
.all([
'eth_accounts',
'eth_coinbase',
'parity_accountsInfo',
'parity_allAccountsInfo',
'parity_changePassword',
'parity_checkRequest',
'parity_defaultAccount',
'parity_generateSecretPhrase',
'parity_getNewDappsAddresses',
'parity_hardwareAccountsInfo',
'parity_newAccountFromPhrase',
'parity_newAccountFromSecret',
'parity_setAccountMeta',
'parity_setAccountName',
'parity_postTransaction',
'parity_phraseToAddress',
'parity_useLocalAccounts',
'parity_listGethAccounts',
'parity_listRecentDapps',
'parity_killAccount',
'parity_testPassword',
'signer_confirmRequest',
'signer_rejectRequest',
'signer_requestsToConfirm'
].map((method) => {
return transport
.execute(method)
.then((result) => {
expect(result).not.to.be.equal(RPC_RESPONSE);
})
// Some errors are expected here since we are calling methods
// without parameters.
.catch((_) => {});
}));
});
it('allows non-registered methods through', () => {
return transport
.execute('eth_getBalance', '0x407d73d8a49eeb85d32cf465507dd71d507100c1')
.then((result) => {
expect(result).to.be.equal(RPC_RESPONSE);
});
});
it('can handle `eth_accounts`', () => {
return transport
.execute('eth_accounts')
.then((accounts) => {
expect(accounts.length).to.be.equal(1);
expect(accounts[0]).to.be.equal(ADDRESS);
});
});
it('can handle `parity_defaultAccount`', () => {
return transport
.execute('parity_defaultAccount')
.then((address) => {
expect(address).to.be.equal(ADDRESS);
});
});
it('can handle `parity_phraseToAddress`', () => {
return transport
.execute('parity_phraseToAddress', '')
.then((address) => {
expect(address).to.be.equal(ADDRESS);
return transport.execute('parity_phraseToAddress', FOO_PHRASE);
})
.then((address) => {
expect(address).to.be.equal(FOO_ADDRESS);
});
});
it('can create and kill an account', () => {
return transport
.execute('parity_newAccountFromPhrase', FOO_PHRASE, FOO_PASSWORD)
.then((address) => {
expect(address).to.be.equal(FOO_ADDRESS);
return transport.execute('eth_accounts');
})
.then((accounts) => {
expect(accounts.length).to.be.equal(2);
expect(accounts.includes(FOO_ADDRESS)).to.be.true;
return transport.execute('parity_killAccount', FOO_ADDRESS, FOO_PASSWORD);
})
.then((result) => {
expect(result).to.be.true;
return transport.execute('eth_accounts');
})
.then((accounts) => {
expect(accounts.length).to.be.equal(1);
expect(accounts.includes(FOO_ADDRESS)).to.be.false;
});
});
});

View File

@ -18,6 +18,7 @@ import { toHex } from '../util/format';
import { TransportError } from '../transport'; import { TransportError } from '../transport';
const AWAITING = Symbol('awaiting'); const AWAITING = Symbol('awaiting');
const LOCKED = Symbol('locked');
const CONFIRMED = Symbol('confirmed'); const CONFIRMED = Symbol('confirmed');
const REJECTED = Symbol('rejected'); const REJECTED = Symbol('rejected');
@ -57,6 +58,26 @@ class Transactions {
return state.transaction; return state.transaction;
} }
lock (id) {
const state = this._states[id];
if (!state || state.status !== AWAITING) {
throw new Error('Trying to lock an invalid transaction');
}
state.status = LOCKED;
}
unlock (id) {
const state = this._states[id];
if (!state || state.status !== LOCKED) {
throw new Error('Trying to unlock an invalid transaction');
}
state.status = AWAITING;
}
hash (id) { hash (id) {
const state = this._states[id]; const state = this._states[id];
@ -76,9 +97,12 @@ class Transactions {
confirm (id, hash) { confirm (id, hash) {
const state = this._states[id]; const state = this._states[id];
const status = state ? state.status : null;
if (!state || state.status !== AWAITING) { switch (status) {
throw new Error('Trying to confirm an invalid transaction'); case AWAITING: break;
case LOCKED: break;
default: throw new Error('Trying to confirm an invalid transaction');
} }
state.hash = hash; state.hash = hash;

View File

@ -65,4 +65,21 @@ describe('api/local/transactions', () => {
expect(requests.length).to.be.equal(0); expect(requests.length).to.be.equal(0);
expect(() => transactions.hash(id)).to.throw(TransportError); expect(() => transactions.hash(id)).to.throw(TransportError);
}); });
it('can lock and confirm transactions', () => {
const id = transactions.add(DUMMY_TX);
const hash = '0x1111111111111111111111111111111111111111';
transactions.lock(id);
const requests = transactions.requestsToConfirm();
expect(requests.length).to.be.equal(0);
expect(transactions.get(id)).to.be.null;
expect(transactions.hash(id)).to.be.null;
transactions.confirm(id, hash);
expect(transactions.hash(id)).to.be.equal(hash);
});
}); });

View File

@ -522,6 +522,11 @@ export default class Parity {
.then(outNumber); .then(outNumber);
} }
signMessage (address, password, messageHash) {
return this._transport
.execute('parity_signMessage', inAddress(address), password, inHex(messageHash));
}
testPassword (account, password) { testPassword (account, password) {
return this._transport return this._transport
.execute('parity_testPassword', inAddress(account), password); .execute('parity_testPassword', inAddress(account), password);

View File

@ -38,20 +38,20 @@ export default class JsonRpcBase extends EventEmitter {
return json; return json;
} }
addMiddleware (middleware) { addMiddleware (Middleware) {
this._middlewareList = Promise this._middlewareList = Promise
.all([ .all([
middleware, Middleware,
this._middlewareList this._middlewareList
]) ])
.then(([middleware, middlewareList]) => { .then(([Middleware, middlewareList]) => {
// Do nothing if `handlerPromise` resolves to a null-y value. // Do nothing if `handlerPromise` resolves to a null-y value.
if (middleware == null) { if (Middleware == null) {
return middlewareList; return middlewareList;
} }
// don't mutate the original array // don't mutate the original array
return middlewareList.concat([middleware]); return middlewareList.concat([new Middleware(this)]);
}); });
} }
@ -80,8 +80,8 @@ export default class JsonRpcBase extends EventEmitter {
const res = middleware.handle(method, params); const res = middleware.handle(method, params);
if (res != null) { if (res != null) {
// If `res` isn't a promise, we need to wrap it return Promise
return Promise.resolve(res) .resolve(res)
.then((res) => { .then((res) => {
const result = this._wrapSuccessResult(res); const result = this._wrapSuccessResult(res);
const json = this.encode(method, params); const json = this.encode(method, params);

View File

@ -28,9 +28,7 @@ export default class Middleware {
const handler = this._handlers[method]; const handler = this._handlers[method];
if (handler != null) { if (handler != null) {
const response = handler(params); return handler(params);
return response;
} }
return null; return null;

View File

@ -25,17 +25,21 @@ class MockTransport extends JsonRpcBase {
} }
} }
class MockMiddleware extends Middleware {
constructor (transport) {
super(transport);
this.register('mock_rpc', ([num]) => num);
this.register('mock_null', () => null);
}
}
describe('api/transport/Middleware', () => { describe('api/transport/Middleware', () => {
let middleware;
let transport; let transport;
beforeEach(() => { beforeEach(() => {
transport = new MockTransport(); transport = new MockTransport();
middleware = new Middleware(transport); transport.addMiddleware(MockMiddleware);
middleware.register('mock_rpc', ([num]) => num);
middleware.register('mock_null', () => null);
transport.addMiddleware(middleware);
}); });
it('Routes requests to middleware', () => { it('Routes requests to middleware', () => {

View File

@ -37,7 +37,7 @@ export default {
params: `An error occurred with the following description` params: `An error occurred with the following description`
}, },
input: { input: {
abi: `ABI Interface`, abi: `ABI Definition`,
code: `Bytecode`, code: `Bytecode`,
metadata: `Metadata`, metadata: `Metadata`,
swarm: `Swarm Metadata Hash` swarm: `Swarm Metadata Hash`

View File

@ -1881,5 +1881,31 @@ export default {
desc: 'Decrypted message.', desc: 'Decrypted message.',
example: withComment('0x68656c6c6f20776f726c64', 'hello world') example: withComment('0x68656c6c6f20776f726c64', 'hello world')
} }
},
signMessage: {
desc: 'Sign the hashed message bytes with the given account.',
params: [
{
type: Address,
desc: 'Account which signs the message.',
example: '0xc171033d5cbff7175f29dfd3a63dda3d6f8f385e'
},
{
type: String,
desc: 'Passphrase to unlock the account.',
example: 'password1'
},
{
type: Data,
desc: 'Hashed message.',
example: '0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a'
}
],
returns: {
type: Data,
desc: 'Message signature.',
example: '0x1d9e33a8cf8bfc089a172bca01da462f9e359c6cb1b0f29398bc884e4d18df4f78588aee4fb5cc067ca62d2abab995e0bba29527be6ac98105b0320020a2efaf00'
}
} }
}; };

View File

@ -96,6 +96,7 @@ export default class Store {
} }
@computed get qrAddressValid () { @computed get qrAddressValid () {
console.log('qrValid', this.qrAddress, this._api.util.isAddressValid(this.qrAddress));
return this._api.util.isAddressValid(this.qrAddress); return this._api.util.isAddressValid(this.qrAddress);
} }
@ -155,7 +156,10 @@ export default class Store {
qrAddress = `0x${qrAddress}`; qrAddress = `0x${qrAddress}`;
} }
this.qrAddress = qrAddress; // FIXME: Current native signer encoding is not 100% for EIP-55, lowercase for now
this.qrAddress = this._api.util
? this._api.util.toChecksumAddress(qrAddress.toLowerCase())
: qrAddress;
} }
@action setVaultName = (vaultName) => { @action setVaultName = (vaultName) => {

View File

@ -69,7 +69,9 @@ const QR_SIZES = [
export function calculateType (lengthBytes, errorLevel = 'M') { export function calculateType (lengthBytes, errorLevel = 'M') {
let type = 5; let type = 5;
while (type < 40 && lengthBytes > QR_SIZES[errorLevel][type - 1]) { // subtract 3 from the capacities, since we need 2 bits for the mode and a
// bunch more for the length.
while (type < 40 && lengthBytes > QR_SIZES[errorLevel][type - 1] - 3) {
type++; type++;
} }

View File

@ -608,7 +608,7 @@ class WriteContract extends Component {
label={ label={
<FormattedMessage <FormattedMessage
id='writeContract.input.abi' id='writeContract.input.abi'
defaultMessage='ABI Interface' defaultMessage='ABI Definition'
/> />
} }
readOnly readOnly

View File

@ -138,7 +138,9 @@ module.exports = {
resolve: { resolve: {
alias: { alias: {
'~': path.resolve(__dirname, '../src') '~': path.resolve(__dirname, '../src'),
'secp256k1': path.resolve(__dirname, '../node_modules/secp256k1/js'),
'keythereum': path.resolve(__dirname, '../node_modules/keythereum/dist/keythereum')
}, },
modules: [ modules: [
path.join(__dirname, '../node_modules') path.join(__dirname, '../node_modules')

View File

@ -41,7 +41,9 @@ module.exports = {
resolve: { resolve: {
alias: { alias: {
'~': path.resolve(__dirname, '../src') '~': path.resolve(__dirname, '../src'),
'secp256k1': path.resolve(__dirname, '../node_modules/secp256k1/js'),
'keythereum': path.resolve(__dirname, '../node_modules/keythereum/dist/keythereum')
} }
}, },

View File

@ -76,7 +76,6 @@ module.exports = {
resolve: { resolve: {
alias: { alias: {
'secp256k1/js': path.resolve(__dirname, '../src/api/local/ethkey/dummy.js'),
'~': path.resolve(__dirname, '../src') '~': path.resolve(__dirname, '../src')
}, },
modules: [ modules: [

View File

@ -8,7 +8,7 @@ use serde::de::{Error, Visitor};
use serde::de::value::ValueDeserializer; use serde::de::value::ValueDeserializer;
/// Deserializer of empty string values into optionals. /// Deserializer of empty string values into optionals.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub enum MaybeEmpty<T> { pub enum MaybeEmpty<T> {
/// Some. /// Some.
Some(T), Some(T),

View File

@ -14,13 +14,16 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! State test deserializer. //! General test deserialization.
use std::collections::BTreeMap;
use std::io::Read; use std::io::Read;
use serde_json; use std::collections::BTreeMap;
use serde_json::Error; use uint::Uint;
use state::State; use bytes::Bytes;
use hash::{Address, H256};
use state::{Env, AccountState, Transaction};
use maybe::MaybeEmpty;
use serde_json::{self, Error};
/// State test deserializer. /// State test deserializer.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
@ -41,3 +44,182 @@ impl Test {
serde_json::from_reader(reader) serde_json::from_reader(reader)
} }
} }
/// State test deserialization.
#[derive(Debug, PartialEq, Deserialize)]
pub struct State {
/// Environment.
pub env: Env,
/// Pre state.
#[serde(rename="pre")]
pub pre_state: AccountState,
/// Post state.
#[serde(rename="post")]
pub post_states: BTreeMap<ForkSpec, Vec<PostStateResult>>,
/// Transaction.
pub transaction: MultiTransaction,
}
/// State test transaction deserialization.
#[derive(Debug, PartialEq, Deserialize)]
pub struct MultiTransaction {
/// Transaction data set.
pub data: Vec<Bytes>,
/// Gas limit set.
#[serde(rename="gasLimit")]
pub gas_limit: Vec<Uint>,
/// Gas price.
#[serde(rename="gasPrice")]
pub gas_price: Uint,
/// Nonce.
pub nonce: Uint,
/// Secret key.
#[serde(rename="secretKey")]
pub secret: H256,
/// To.
pub to: MaybeEmpty<Address>,
/// Value set.
pub value: Vec<Uint>,
}
impl MultiTransaction {
/// Build transaction with given indexes.
pub fn select(&self, indexes: &PostStateIndexes) -> Transaction {
Transaction {
data: self.data[indexes.data as usize].clone(),
gas_limit: self.gas_limit[indexes.gas as usize].clone(),
gas_price: self.gas_price.clone(),
nonce: self.nonce.clone(),
secret: self.secret.clone(),
to: self.to.clone(),
value: self.value[indexes.value as usize].clone(),
}
}
}
/// State test transaction deserialization.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
pub enum ForkSpec {
EIP150,
EIP158,
Frontier,
Homestead,
Metropolis,
}
/// State test indexes deserialization.
#[derive(Debug, PartialEq, Deserialize)]
pub struct PostStateIndexes {
/// Index into transaction data set.
pub data: u64,
/// Index into transaction gas limit set.
pub gas: u64,
/// Index into transaction value set.
pub value: u64,
}
/// State test indexed state result deserialization.
#[derive(Debug, PartialEq, Deserialize)]
pub struct PostStateResult {
/// Post state hash
pub hash: H256,
/// Indexes
pub indexes: PostStateIndexes,
}
#[cfg(test)]
mod tests {
use serde_json;
use super::{MultiTransaction, State};
#[test]
fn multi_transaction_deserialization() {
let s = r#"{
"data" : [ "" ],
"gasLimit" : [ "0x2dc6c0", "0x222222" ],
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "1000000000000000000000000000000000000000",
"value" : [ "0x00", "0x01", "0x02" ]
}"#;
let _deserialized: MultiTransaction = serde_json::from_str(s).unwrap();
}
#[test]
fn state_deserialization() {
let s = r#"{
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "0x0100",
"currentGasLimit" : "0x01c9c380",
"currentNumber" : "0x00",
"currentTimestamp" : "0x01",
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"post" : {
"EIP150" : [
{
"hash" : "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
"indexes" : { "data" : 0, "gas" : 0, "value" : 0 }
},
{
"hash" : "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764",
"indexes" : { "data" : 0, "gas" : 0, "value" : 1 }
}
],
"EIP158" : [
{
"hash" : "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
"indexes" : { "data" : 0, "gas" : 0, "value" : 0 }
},
{
"hash" : "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764",
"indexes" : { "data" : 0, "gas" : 0, "value" : 1 }
}
]
},
"pre" : {
"1000000000000000000000000000000000000000" : {
"balance" : "0x0de0b6b3a7640000",
"code" : "0x6040600060406000600173100000000000000000000000000000000000000162055730f1600055",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000001" : {
"balance" : "0x0de0b6b3a7640000",
"code" : "0x604060006040600060027310000000000000000000000000000000000000026203d090f1600155",
"nonce" : "0x00",
"storage" : {
}
},
"1000000000000000000000000000000000000002" : {
"balance" : "0x00",
"code" : "0x600160025533600455346007553060e6553260e8553660ec553860ee553a60f055",
"nonce" : "0x00",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x0de0b6b3a7640000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
}
},
"transaction" : {
"data" : [ "" ],
"gasLimit" : [ "285000", "100000", "6000" ],
"gasPrice" : "0x01",
"nonce" : "0x00",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : [ "10", "0" ]
}
}"#;
let _deserialized: State = serde_json::from_str(s).unwrap();
// TODO: validate all fields
}
}

View File

@ -192,6 +192,10 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
info!("Starting {}", Colour::White.bold().paint(version())); info!("Starting {}", Colour::White.bold().paint(version()));
info!("Running in experimental {} mode.", Colour::Blue.bold().paint("Light Client")); info!("Running in experimental {} mode.", Colour::Blue.bold().paint("Light Client"));
// TODO: configurable cache size.
let cache = LightDataCache::new(Default::default(), ::time::Duration::minutes(GAS_CORPUS_EXPIRATION_MINUTES));
let cache = Arc::new(::util::Mutex::new(cache));
// start client and create transaction queue. // start client and create transaction queue.
let mut config = light_client::Config { let mut config = light_client::Config {
queue: Default::default(), queue: Default::default(),
@ -204,7 +208,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024; config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
config.queue.verifier_settings = cmd.verifier_settings; config.queue.verifier_settings = cmd.verifier_settings;
let service = light_client::Service::start(config, &spec, &db_dirs.client_path(algorithm)) let service = light_client::Service::start(config, &spec, &db_dirs.client_path(algorithm), cache.clone())
.map_err(|e| format!("Error starting light client: {}", e))?; .map_err(|e| format!("Error starting light client: {}", e))?;
let txq = Arc::new(RwLock::new(::light::transaction_queue::TransactionQueue::default())); let txq = Arc::new(RwLock::new(::light::transaction_queue::TransactionQueue::default()));
let provider = ::light::provider::LightProvider::new(service.client().clone(), txq.clone()); let provider = ::light::provider::LightProvider::new(service.client().clone(), txq.clone());
@ -216,10 +220,6 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
net_conf.boot_nodes = spec.nodes.clone(); net_conf.boot_nodes = spec.nodes.clone();
} }
// TODO: configurable cache size.
let cache = LightDataCache::new(Default::default(), ::time::Duration::minutes(GAS_CORPUS_EXPIRATION_MINUTES));
let cache = Arc::new(::util::Mutex::new(cache));
// start on_demand service. // start on_demand service.
let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone())); let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone()));

View File

@ -475,7 +475,7 @@ pub fn execute<D: Dispatcher + 'static>(
.map(ConfirmationResponse::SignTransaction) .map(ConfirmationResponse::SignTransaction)
).boxed() ).boxed()
}, },
ConfirmationPayload::Signature(address, mut data) => { ConfirmationPayload::EthSignMessage(address, mut data) => {
let mut message_data = let mut message_data =
format!("\x19Ethereum Signed Message:\n{}", data.len()) format!("\x19Ethereum Signed Message:\n{}", data.len())
.into_bytes(); .into_bytes();
@ -575,8 +575,8 @@ pub fn from_rpc<D>(payload: RpcConfirmationPayload, default_account: Address, di
RpcConfirmationPayload::Decrypt(RpcDecryptRequest { address, msg }) => { RpcConfirmationPayload::Decrypt(RpcDecryptRequest { address, msg }) => {
future::ok(ConfirmationPayload::Decrypt(address.into(), msg.into())).boxed() future::ok(ConfirmationPayload::Decrypt(address.into(), msg.into())).boxed()
}, },
RpcConfirmationPayload::Signature(RpcSignRequest { address, data }) => { RpcConfirmationPayload::EthSignMessage(RpcSignRequest { address, data }) => {
future::ok(ConfirmationPayload::Signature(address.into(), data.into())).boxed() future::ok(ConfirmationPayload::EthSignMessage(address.into(), data.into())).boxed()
}, },
} }
} }

View File

@ -36,7 +36,7 @@ use light::on_demand::{OnDemand, request};
use ethsync::LightSync; use ethsync::LightSync;
use util::{Address, Mutex, Uint, U256}; use util::{Address, Mutex, Uint, U256};
use v1::helpers::{CallRequest as CRequest, errors, dispatch}; use v1::helpers::{CallRequest as CallRequestHelper, errors, dispatch};
use v1::types::{BlockNumber, CallRequest}; use v1::types::{BlockNumber, CallRequest};
/// Helper for fetching blockchain data either from the light client or the network /// Helper for fetching blockchain data either from the light client or the network
@ -129,7 +129,7 @@ impl LightFetch {
const DEFAULT_GAS_PRICE: U256 = U256([0, 0, 0, 21_000_000]); const DEFAULT_GAS_PRICE: U256 = U256([0, 0, 0, 21_000_000]);
let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone()); let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone());
let req: CRequest = req.into(); let req: CallRequestHelper = req.into();
let id = num.0.into(); let id = num.0.into();
let from = req.from.unwrap_or(Address::zero()); let from = req.from.unwrap_or(Address::zero());

View File

@ -113,8 +113,8 @@ pub enum ConfirmationPayload {
SendTransaction(FilledTransactionRequest), SendTransaction(FilledTransactionRequest),
/// Sign Transaction /// Sign Transaction
SignTransaction(FilledTransactionRequest), SignTransaction(FilledTransactionRequest),
/// Sign request /// Sign a message with an Ethereum specific security prefix.
Signature(Address, Bytes), EthSignMessage(Address, Bytes),
/// Decrypt request /// Decrypt request
Decrypt(Address, Bytes), Decrypt(Address, Bytes),
} }
@ -124,7 +124,7 @@ impl ConfirmationPayload {
match *self { match *self {
ConfirmationPayload::SendTransaction(ref request) => request.from, ConfirmationPayload::SendTransaction(ref request) => request.from,
ConfirmationPayload::SignTransaction(ref request) => request.from, ConfirmationPayload::SignTransaction(ref request) => request.from,
ConfirmationPayload::Signature(ref address, _) => *address, ConfirmationPayload::EthSignMessage(ref address, _) => *address,
ConfirmationPayload::Decrypt(ref address, _) => *address, ConfirmationPayload::Decrypt(ref address, _) => *address,
} }
} }

View File

@ -475,15 +475,18 @@ impl Filterable for EthClient {
use util::H2048; use util::H2048;
// early exit for "to" block before "from" block. // early exit for "to" block before "from" block.
match filter.from_block { let best_number = self.client.chain_info().best_block_number;
BlockId::Latest | BlockId::Pending => { let block_number = |id| match id {
let best = self.client.best_block_header(); BlockId::Earliest => Some(0),
let chain_info = self.client.chain_info(); BlockId::Latest | BlockId::Pending => Some(best_number),
if best.number() != chain_info.best_block_number || best.hash() != chain_info.best_block_hash { BlockId::Hash(h) => self.client.block_header(BlockId::Hash(h)).map(|hdr| hdr.number()),
return future::ok(Vec::new()).boxed() BlockId::Number(x) => Some(x),
} };
}
_ => {} match (block_number(filter.to_block), block_number(filter.from_block)) {
(Some(to), Some(from)) if to < from => return future::ok(Vec::new()).boxed(),
(Some(_), Some(_)) => {},
_ => return future::err(errors::unknown_block()).boxed(),
} }
let maybe_future = self.sync.with_context(move |ctx| { let maybe_future = self.sync.with_context(move |ctx| {

View File

@ -17,7 +17,7 @@
//! Account management (personal) rpc implementation //! Account management (personal) rpc implementation
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use util::{Address}; use util::Address;
use ethkey::{Brain, Generator, Secret}; use ethkey::{Brain, Generator, Secret};
use ethstore::KeyFile; use ethstore::KeyFile;
@ -27,7 +27,7 @@ use jsonrpc_core::Error;
use v1::helpers::errors; use v1::helpers::errors;
use v1::helpers::accounts::unwrap_provider; use v1::helpers::accounts::unwrap_provider;
use v1::traits::ParityAccounts; use v1::traits::ParityAccounts;
use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId, Derive, DeriveHierarchical, DeriveHash}; use v1::types::{H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, DappId, Derive, DeriveHierarchical, DeriveHash};
/// Account management (personal) rpc implementation. /// Account management (personal) rpc implementation.
pub struct ParityAccountsClient { pub struct ParityAccountsClient {
@ -334,6 +334,17 @@ impl ParityAccounts for ParityAccountsClient {
.map(Into::into) .map(Into::into)
.map_err(|e| errors::account("Could not export account.", e)) .map_err(|e| errors::account("Could not export account.", e))
} }
fn sign_message(&self, addr: RpcH160, password: String, message: RpcH256) -> Result<RpcH520, Error> {
self.account_provider()?
.sign(
addr.into(),
Some(password),
message.into()
)
.map(Into::into)
.map_err(|e| errors::account("Could not sign message.", e))
}
} }
fn into_vec<A, B>(a: Vec<A>) -> Vec<B> where fn into_vec<A, B>(a: Vec<A>) -> Vec<B> where

View File

@ -140,7 +140,7 @@ impl<D: Dispatcher + 'static> ParitySigning for SigningQueueClient<D> {
fn post_sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> { fn post_sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
let pending = self.pending.clone(); let pending = self.pending.clone();
self.dispatch( self.dispatch(
RpcConfirmationPayload::Signature((address.clone(), data).into()), RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()),
DefaultAccount::Provided(address.into()), DefaultAccount::Provided(address.into()),
meta.origin meta.origin
).map(move |result| match result { ).map(move |result| match result {
@ -216,7 +216,7 @@ impl<D: Dispatcher + 'static> EthSigning for SigningQueueClient<D> {
fn sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> { fn sign(&self, meta: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> {
let res = self.dispatch( let res = self.dispatch(
RpcConfirmationPayload::Signature((address.clone(), data).into()), RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()),
address.into(), address.into(),
meta.origin, meta.origin,
); );

View File

@ -78,7 +78,7 @@ impl<D: Dispatcher + 'static> EthSigning for SigningUnsafeClient<D>
type Metadata = Metadata; type Metadata = Metadata;
fn sign(&self, _: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> { fn sign(&self, _: Metadata, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> {
self.handle(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into()) self.handle(RpcConfirmationPayload::EthSignMessage((address.clone(), data).into()), address.into())
.then(|res| match res { .then(|res| match res {
Ok(RpcConfirmationResponse::Signature(signature)) => Ok(signature), Ok(RpcConfirmationResponse::Signature(signature)) => Ok(signature),
Err(e) => Err(e), Err(e) => Err(e),

View File

@ -500,3 +500,20 @@ fn should_export_account() {
println!("Response: {:?}", response); println!("Response: {:?}", response);
assert_eq!(result, Some(response.into())); assert_eq!(result, Some(response.into()));
} }
#[test]
fn should_sign_message() {
let tester = setup();
let hash = tester.accounts
.insert_account(
"0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a".parse().unwrap(),
"password1")
.expect("account should be inserted ok");
assert_eq!(hash, "c171033d5cbff7175f29dfd3a63dda3d6f8f385e".parse().unwrap());
let request = r#"{"jsonrpc": "2.0", "method": "parity_signMessage", "params": ["0xc171033d5cbff7175f29dfd3a63dda3d6f8f385e", "password1", "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"], "id": 3}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x1d9e33a8cf8bfc089a172bca01da462f9e359c6cb1b0f29398bc884e4d18df4f78588aee4fb5cc067ca62d2abab995e0bba29527be6ac98105b0320020a2efaf00","id":3}"#;
let res = tester.io.handle_request_sync(&request);
assert_eq!(res, Some(response.into()));
}

View File

@ -90,7 +90,7 @@ fn should_return_list_of_items_to_confirm() {
nonce: None, nonce: None,
condition: None, condition: None,
}), Origin::Dapps("http://parity.io".into())).unwrap(); }), Origin::Dapps("http://parity.io".into())).unwrap();
tester.signer.add_request(ConfirmationPayload::Signature(1.into(), vec![5].into()), Origin::Unknown).unwrap(); tester.signer.add_request(ConfirmationPayload::EthSignMessage(1.into(), vec![5].into()), Origin::Unknown).unwrap();
// when // when
let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#; let request = r#"{"jsonrpc":"2.0","method":"signer_requestsToConfirm","params":[],"id":1}"#;
@ -163,7 +163,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
fn should_not_remove_sign_if_password_is_invalid() { fn should_not_remove_sign_if_password_is_invalid() {
// given // given
let tester = signer_tester(); let tester = signer_tester();
tester.signer.add_request(ConfirmationPayload::Signature(0.into(), vec![5].into()), Origin::Unknown).unwrap(); tester.signer.add_request(ConfirmationPayload::EthSignMessage(0.into(), vec![5].into()), Origin::Unknown).unwrap();
assert_eq!(tester.signer.requests().len(), 1); assert_eq!(tester.signer.requests().len(), 1);
// when // when

View File

@ -19,7 +19,7 @@ use std::collections::BTreeMap;
use jsonrpc_core::Error; use jsonrpc_core::Error;
use ethstore::KeyFile; use ethstore::KeyFile;
use v1::types::{H160, H256, DappId, DeriveHash, DeriveHierarchical}; use v1::types::{H160, H256, H520, DappId, DeriveHash, DeriveHierarchical};
build_rpc_trait! { build_rpc_trait! {
/// Personal Parity rpc interface. /// Personal Parity rpc interface.
@ -180,5 +180,9 @@ build_rpc_trait! {
/// Exports an account with given address if provided password matches. /// Exports an account with given address if provided password matches.
#[rpc(name = "parity_exportAccount")] #[rpc(name = "parity_exportAccount")]
fn export_account(&self, H160, String) -> Result<KeyFile, Error>; fn export_account(&self, H160, String) -> Result<KeyFile, Error>;
/// Sign raw hash with the key corresponding to address and password.
#[rpc(name = "parity_signMessage")]
fn sign_message(&self, H160, String, H256) -> Result<H520, Error>;
} }
} }

View File

@ -57,7 +57,7 @@ impl fmt::Display for ConfirmationPayload {
match *self { match *self {
ConfirmationPayload::SendTransaction(ref transaction) => write!(f, "{}", transaction), ConfirmationPayload::SendTransaction(ref transaction) => write!(f, "{}", transaction),
ConfirmationPayload::SignTransaction(ref transaction) => write!(f, "(Sign only) {}", transaction), ConfirmationPayload::SignTransaction(ref transaction) => write!(f, "(Sign only) {}", transaction),
ConfirmationPayload::Signature(ref sign) => write!(f, "{}", sign), ConfirmationPayload::EthSignMessage(ref sign) => write!(f, "{}", sign),
ConfirmationPayload::Decrypt(ref decrypt) => write!(f, "{}", decrypt), ConfirmationPayload::Decrypt(ref decrypt) => write!(f, "{}", decrypt),
} }
} }
@ -169,7 +169,7 @@ pub enum ConfirmationPayload {
SignTransaction(TransactionRequest), SignTransaction(TransactionRequest),
/// Signature /// Signature
#[serde(rename="sign")] #[serde(rename="sign")]
Signature(SignRequest), EthSignMessage(SignRequest),
/// Decryption /// Decryption
#[serde(rename="decrypt")] #[serde(rename="decrypt")]
Decrypt(DecryptRequest), Decrypt(DecryptRequest),
@ -180,7 +180,7 @@ impl From<helpers::ConfirmationPayload> for ConfirmationPayload {
match c { match c {
helpers::ConfirmationPayload::SendTransaction(t) => ConfirmationPayload::SendTransaction(t.into()), helpers::ConfirmationPayload::SendTransaction(t) => ConfirmationPayload::SendTransaction(t.into()),
helpers::ConfirmationPayload::SignTransaction(t) => ConfirmationPayload::SignTransaction(t.into()), helpers::ConfirmationPayload::SignTransaction(t) => ConfirmationPayload::SignTransaction(t.into()),
helpers::ConfirmationPayload::Signature(address, data) => ConfirmationPayload::Signature(SignRequest { helpers::ConfirmationPayload::EthSignMessage(address, data) => ConfirmationPayload::EthSignMessage(SignRequest {
address: address.into(), address: address.into(),
data: data.into(), data: data.into(),
}), }),
@ -255,7 +255,7 @@ mod tests {
// given // given
let request = helpers::ConfirmationRequest { let request = helpers::ConfirmationRequest {
id: 15.into(), id: 15.into(),
payload: helpers::ConfirmationPayload::Signature(1.into(), vec![5].into()), payload: helpers::ConfirmationPayload::EthSignMessage(1.into(), vec![5].into()),
origin: Origin::Rpc("test service".into()), origin: Origin::Rpc("test service".into()),
}; };

View File

@ -2132,7 +2132,7 @@ impl ChainSync {
let queue_info = io.chain().queue_info(); let queue_info = io.chain().queue_info();
let is_syncing = self.status().is_syncing(queue_info); let is_syncing = self.status().is_syncing(queue_info);
if !is_syncing || !sealed.is_empty() { if !is_syncing || !sealed.is_empty() || !proposed.is_empty() {
trace!(target: "sync", "Propagating blocks, state={:?}", self.state); trace!(target: "sync", "Propagating blocks, state={:?}", self.state);
self.propagate_latest_blocks(io, sealed); self.propagate_latest_blocks(io, sealed);
self.propagate_proposed_blocks(io, proposed); self.propagate_proposed_blocks(io, proposed);

View File

@ -32,6 +32,9 @@ use light::provider::LightProvider;
use network::{NodeId, PeerId}; use network::{NodeId, PeerId};
use util::RwLock; use util::RwLock;
use time::Duration;
use light::cache::Cache;
const NETWORK_ID: u64 = 0xcafebabe; const NETWORK_ID: u64 = 0xcafebabe;
struct TestIoContext<'a> { struct TestIoContext<'a> {
@ -207,7 +210,8 @@ impl TestNet<Peer> {
pub fn light(n_light: usize, n_full: usize) -> Self { pub fn light(n_light: usize, n_full: usize) -> Self {
let mut peers = Vec::with_capacity(n_light + n_full); let mut peers = Vec::with_capacity(n_light + n_full);
for _ in 0..n_light { for _ in 0..n_light {
let client = LightClient::in_memory(Default::default(), &Spec::new_test(), IoChannel::disconnected()); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let client = LightClient::in_memory(Default::default(), &Spec::new_test(), IoChannel::disconnected(), cache);
peers.push(Arc::new(Peer::new_light(Arc::new(client)))) peers.push(Arc::new(Peer::new_light(Arc::new(client))))
} }

View File

@ -196,8 +196,8 @@ fn tendermint() {
// Propose // Propose
net.peer(0).chain.engine().step(); net.peer(0).chain.engine().step();
net.peer(1).chain.engine().step(); net.peer(1).chain.engine().step();
net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into())).unwrap(); net.peer(0).chain.miner().import_own_transaction(&*net.peer(0).chain, new_tx(s0.secret(), 2.into())).unwrap();
net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into())).unwrap(); net.peer(1).chain.miner().import_own_transaction(&*net.peer(1).chain, new_tx(s1.secret(), 2.into())).unwrap();
// Send different prevotes // Send different prevotes
net.sync(); net.sync();
// Prevote timeout // Prevote timeout

View File

@ -277,31 +277,32 @@ impl TestNet<EthPeer<EthcoreClient>> {
started: false, started: false,
disconnect_events: Vec::new(), disconnect_events: Vec::new(),
}; };
for _ in 0..n { for _ in 0..n {
let spec = spec_factory(); net.add_peer(config.clone(), spec_factory(), accounts.clone());
let client = EthcoreClient::new(
ClientConfig::default(),
&spec,
Arc::new(::util::kvdb::in_memory(::ethcore::db::NUM_COLUMNS.unwrap_or(0))),
Arc::new(Miner::with_spec_and_accounts(&spec, accounts.clone())),
IoChannel::disconnected(),
).unwrap();
let ss = Arc::new(TestSnapshotService::new());
let sync = ChainSync::new(config.clone(), &*client);
let peer = Arc::new(EthPeer {
sync: RwLock::new(sync),
snapshot_service: ss,
chain: client,
queue: RwLock::new(VecDeque::new()),
});
peer.chain.add_notify(peer.clone());
net.peers.push(peer);
} }
net net
} }
pub fn add_peer(&mut self, config: SyncConfig, spec: Spec, accounts: Option<Arc<AccountProvider>>) {
let client = EthcoreClient::new(
ClientConfig::default(),
&spec,
Arc::new(::util::kvdb::in_memory(::ethcore::db::NUM_COLUMNS.unwrap_or(0))),
Arc::new(Miner::with_spec_and_accounts(&spec, accounts)),
IoChannel::disconnected(),
).unwrap();
let ss = Arc::new(TestSnapshotService::new());
let sync = ChainSync::new(config, &*client);
let peer = Arc::new(EthPeer {
sync: RwLock::new(sync),
snapshot_service: ss,
chain: client,
queue: RwLock::new(VecDeque::new()),
});
peer.chain.add_notify(peer.clone());
self.peers.push(peer);
}
} }
impl<P> TestNet<P> where P: Peer { impl<P> TestNet<P> where P: Peer {