Merge branch 'master' into on-demand-priority
This commit is contained in:
		
						commit
						a98052fe74
					
				
							
								
								
									
										6
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -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)", | ||||||
| ] | ] | ||||||
|  | |||||||
| @ -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>, | ||||||
|  | |||||||
| @ -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.
 | ||||||
|  | |||||||
| @ -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()) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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.
 | ||||||
|  | |||||||
| @ -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(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -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.
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,7 +14,8 @@ | |||||||
| 				"eip155Transition": "0x7fffffffffffffff", | 				"eip155Transition": "0x7fffffffffffffff", | ||||||
| 				"eip160Transition": "0x7fffffffffffffff", | 				"eip160Transition": "0x7fffffffffffffff", | ||||||
| 				"eip161abcTransition": "0x7fffffffffffffff", | 				"eip161abcTransition": "0x7fffffffffffffff", | ||||||
| 				"eip161dTransition": "0x7fffffffffffffff" | 				"eip161dTransition": "0x7fffffffffffffff", | ||||||
|  | 				"maxCodeSize": 24576 | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
|  | |||||||
| @ -14,7 +14,8 @@ | |||||||
| 				"eip155Transition": "0x7fffffffffffffff", | 				"eip155Transition": "0x7fffffffffffffff", | ||||||
| 				"eip160Transition": "0x0", | 				"eip160Transition": "0x0", | ||||||
| 				"eip161abcTransition": "0x0", | 				"eip161abcTransition": "0x0", | ||||||
| 				"eip161dTransition": "0x0" | 				"eip161dTransition": "0x0", | ||||||
|  | 				"maxCodeSize": 24576 | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
|  | |||||||
| @ -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)); | ||||||
|  | |||||||
| @ -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()); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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] | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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"} |  | ||||||
| @ -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"} |  | ||||||
| @ -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::*; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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"} |  | ||||||
| @ -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; | ||||||
|  | |||||||
| @ -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"} |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -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, []); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -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()) | ||||||
|  | |||||||
| @ -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 | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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"] | ||||||
|  | |||||||
| @ -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) | ||||||
|  | |||||||
| @ -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"); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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), | ||||||
|  | |||||||
| @ -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, | ||||||
|  | |||||||
| @ -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}; | ||||||
|  | |||||||
| @ -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)] | ||||||
|  | |||||||
| @ -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] | ||||||
|  | |||||||
| @ -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>", | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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)
 |  | ||||||
| } |  | ||||||
| @ -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); | ||||||
|  | |||||||
| @ -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); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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); | ||||||
|  |         } | ||||||
|       }; |       }; | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -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'; | ||||||
|  | |||||||
| @ -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, | ||||||
							
								
								
									
										154
									
								
								js/src/api/local/localAccountsMiddleware.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								js/src/api/local/localAccountsMiddleware.spec.js
									
									
									
									
									
										Normal 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; | ||||||
|  |       }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @ -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; | ||||||
|  | |||||||
| @ -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); | ||||||
|  |   }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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', () => { | ||||||
|  | |||||||
| @ -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` | ||||||
|  | |||||||
| @ -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' | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -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) => { | ||||||
|  | |||||||
| @ -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++; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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') | ||||||
|  | |||||||
| @ -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') | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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: [ | ||||||
|  | |||||||
| @ -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), | ||||||
|  | |||||||
| @ -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
 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -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())); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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() | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -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()); | ||||||
|  | |||||||
| @ -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, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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| { | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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, | ||||||
| 		); | 		); | ||||||
|  | |||||||
| @ -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), | ||||||
|  | |||||||
| @ -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())); | ||||||
|  | } | ||||||
|  | |||||||
| @ -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
 | ||||||
|  | |||||||
| @ -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>; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -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()), | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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)))) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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
 | ||||||
|  | |||||||
| @ -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 { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user