From 2cf0f1b5f3a10fbddfe3649e6ba0442544edbb8e Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 11 Feb 2016 14:35:03 +0100 Subject: [PATCH 001/753] moved chainfilter from util to ethcore, blockchain stores block blooms --- ethcore/src/blockchain.rs | 26 ++++++++++++++++---------- {util => ethcore}/src/chainfilter.rs | 15 ++++++++------- ethcore/src/client.rs | 2 +- ethcore/src/lib.rs | 1 + ethcore/src/tests/helpers.rs | 4 ++-- util/src/lib.rs | 2 -- 6 files changed, 28 insertions(+), 22 deletions(-) rename {util => ethcore}/src/chainfilter.rs (98%) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 9240ff800..270dfc459 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -22,6 +22,7 @@ use header::*; use extras::*; use transaction::*; use views::*; +use receipt::Receipt; /// Represents a tree route between `from` block and `to` block: pub struct TreeRoute { @@ -425,7 +426,7 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, bytes: &[u8]) { + pub fn insert_block(&self, bytes: &[u8], receipts: &[Receipt]) { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -437,7 +438,7 @@ impl BlockChain { // store block in db self.blocks_db.put(&hash, &bytes).unwrap(); - let (batch, new_best, details) = self.block_to_extras_insert_batch(bytes); + let (batch, new_best, details) = self.block_to_extras_insert_batch(bytes, receipts); // update best block let mut best_block = self.best_block.write().unwrap(); @@ -457,7 +458,7 @@ impl BlockChain { /// Transforms block into WriteBatch that may be written into database /// Additionally, if it's new best block it returns new best block object. - fn block_to_extras_insert_batch(&self, bytes: &[u8]) -> (WriteBatch, Option, BlockDetails) { + fn block_to_extras_insert_batch(&self, bytes: &[u8], receipts: &[Receipt]) -> (WriteBatch, Option, BlockDetails) { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -495,6 +496,11 @@ impl BlockChain { }); } + // update block blooms + batch.put_extras(&hash, &BlockLogBlooms { + blooms: receipts.iter().map(|r| r.log_bloom.clone()).collect() + }); + // if it's not new best block, just return if !is_new_best { return (batch, None, details); @@ -682,7 +688,7 @@ mod tests { let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); - bc.insert_block(&first); + bc.insert_block(&first, &[]); let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap(); @@ -715,10 +721,10 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); - bc.insert_block(&b1); - bc.insert_block(&b2); - bc.insert_block(&b3a); - bc.insert_block(&b3b); + bc.insert_block(&b1, &[]); + bc.insert_block(&b2, &[]); + bc.insert_block(&b3a, &[]); + bc.insert_block(&b3b, &[]); assert_eq!(bc.best_block_hash(), best_block_hash); assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0); @@ -795,7 +801,7 @@ mod tests { { let bc = BlockChain::new(&genesis, temp.as_path()); assert_eq!(bc.best_block_hash(), genesis_hash); - bc.insert_block(&b1); + bc.insert_block(&b1, &[]); assert_eq!(bc.best_block_hash(), b1_hash); } @@ -854,7 +860,7 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); - bc.insert_block(&b1); + bc.insert_block(&b1, &[]); let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); diff --git a/util/src/chainfilter.rs b/ethcore/src/chainfilter.rs similarity index 98% rename from util/src/chainfilter.rs rename to ethcore/src/chainfilter.rs index 20462c698..4043a1fee 100644 --- a/util/src/chainfilter.rs +++ b/ethcore/src/chainfilter.rs @@ -16,12 +16,13 @@ //! Multilevel blockchain bloom filter. //! -//! ``` +//! ```not_run //! extern crate ethcore_util as util; +//! extern crate ethcore; //! use std::str::FromStr; -//! use util::chainfilter::*; //! use util::sha3::*; //! use util::hash::*; +//! use ethcore::chainfilter::*; //! //! fn main() { //! let (index_size, bloom_levels) = (16, 3); @@ -55,8 +56,8 @@ //! ``` //! use std::collections::{HashMap}; -use hash::*; -use sha3::*; +use util::hash::*; +use util::sha3::*; /// Represents bloom index in cache /// @@ -350,10 +351,10 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource #[cfg(test)] mod tests { - use hash::*; - use chainfilter::*; - use sha3::*; use std::str::FromStr; + use util::hash::*; + use chainfilter::*; + use util::sha3::*; #[test] fn test_level_size() { diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 5d6537b24..d9e461024 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -304,7 +304,7 @@ impl Client { good_blocks.push(header.hash().clone()); - self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? + self.chain.write().unwrap().insert_block(&block.bytes, result.block().receipts()); //TODO: err here? let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { Ok(_) => (), diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 6c4535339..4f283ef05 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -118,6 +118,7 @@ mod account_db; mod action_params; mod null_engine; mod builtin; +mod chainfilter; mod extras; mod substate; mod executive; diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 93e3e0a0d..0a2b95e8d 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -224,7 +224,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult { @@ -237,7 +237,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes let temp = RandomTempPath::new(); let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); for block_order in 1..block_number { - bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None)); + bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), &[]); } GuardedTempResult:: { diff --git a/util/src/lib.rs b/util/src/lib.rs index bdd595014..6d9991e1d 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -121,7 +121,6 @@ pub mod memorydb; pub mod overlaydb; pub mod journaldb; mod math; -pub mod chainfilter; pub mod crypto; pub mod triehash; pub mod trie; @@ -143,7 +142,6 @@ pub use memorydb::*; pub use overlaydb::*; pub use journaldb::*; pub use math::*; -pub use chainfilter::*; pub use crypto::*; pub use triehash::*; pub use trie::*; From 160c52a14bd19fb41d1f5093e8a17eb56524a637 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 12 Feb 2016 00:40:45 +0100 Subject: [PATCH 002/753] bloomfilters connected to blockchain (but without reversion) --- ethcore/src/blockchain.rs | 73 +++++++++++++++++++++++++++++++++---- ethcore/src/chainfilter.rs | 12 +++--- ethcore/src/extras.rs | 14 +++++++ ethcore/src/verification.rs | 4 ++ 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 270dfc459..3c2fe3a37 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -23,6 +23,10 @@ use extras::*; use transaction::*; use views::*; use receipt::Receipt; +use chainfilter::{ChainFilter, BloomIndex, FilterDataSource}; + +const BLOOM_INDEX_SIZE: usize = 16; +const BLOOM_LEVELS: u8 = 3; /// Represents a tree route between `from` block and `to` block: pub struct TreeRoute { @@ -131,6 +135,9 @@ pub trait BlockProvider { fn genesis_header(&self) -> Header { self.block_header(&self.genesis_hash()).unwrap() } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec; } #[derive(Debug, Hash, Eq, PartialEq, Clone)] @@ -167,6 +174,17 @@ pub struct BlockChain { blocks_db: DB, cache_man: RwLock, + + // blooms config + bloom_index_size: usize, + bloom_levels: u8 +} + +impl FilterDataSource for BlockChain { + fn bloom_at_index(&self, bloom_index: &BloomIndex) -> Option { + let location = self.blocks_bloom_location(bloom_index); + self.blocks_blooms(&location.hash).and_then(|blooms| blooms.blooms.into_iter().nth(location.index).cloned()) + } } impl BlockProvider for BlockChain { @@ -215,6 +233,12 @@ impl BlockProvider for BlockChain { fn transaction_address(&self, hash: &H256) -> Option { self.query_extras(hash, &self.transaction_addresses) } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { + let filter = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels); + filter.blocks_with_bloom(bloom, from_block as usize, to_block as usize).into_iter().map(|b| b as BlockNumber).collect() + } } const COLLECTION_QUEUE_SIZE: usize = 8; @@ -274,6 +298,8 @@ impl BlockChain { extras_db: extras_db, blocks_db: blocks_db, cache_man: RwLock::new(cache_man), + bloom_index_size: BLOOM_INDEX_SIZE, + bloom_levels: BLOOM_LEVELS }; // load best block @@ -497,8 +523,23 @@ impl BlockChain { } // update block blooms + let blooms: Vec = receipts.iter().map(|r| r.log_bloom.clone()).collect(); + + let modified_blooms = { + let filter = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels); + let bloom = blooms.iter().fold(H2048::new(), | ref acc, b | acc | b); + filter.add_bloom(&bloom, header.number() as usize) + }; + + for (bloom_index, bloom) in modified_blooms.into_iter() { + let location = self.blocks_bloom_location(&bloom_index); + let mut blocks_blooms = self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new); + blocks_blooms.blooms[location.index] = bloom; + batch.put_extras(&location.hash, &blocks_blooms); + } + batch.put_extras(&hash, &BlockLogBlooms { - blooms: receipts.iter().map(|r| r.log_bloom.clone()).collect() + blooms: blooms }); // if it's not new best block, just return @@ -541,11 +582,6 @@ impl BlockChain { (batch, Some(best_block), details) } - /// Returns true if transaction is known. - pub fn is_known_transaction(&self, hash: &H256) -> bool { - self.query_extras_exist(hash, &self.transaction_addresses) - } - /// Get best block hash. pub fn best_block_hash(&self) -> H256 { self.best_block.read().unwrap().hash.clone() @@ -562,10 +598,32 @@ impl BlockChain { } /// Get the transactions' log blooms of a block. - pub fn log_blooms(&self, hash: &H256) -> Option { + fn log_blooms(&self, hash: &H256) -> Option { self.query_extras(hash, &self.block_logs) } + /// Get block blooms. + fn blocks_blooms(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.blocks_blooms) + } + + /// Calculates bloom's position in database. + fn blocks_bloom_location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { + use std::{mem, ptr}; + + let hash = unsafe { + let mut hash: H256 = mem::zeroed(); + ptr::copy(&[bloom_index.index / self.bloom_index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); + hash[8] = bloom_index.level; + hash + }; + + BlocksBloomLocation { + hash: hash, + index: bloom_index.index % self.bloom_index_size + } + } + fn query_extras(&self, hash: &K, cache: &RwLock>) -> Option where T: Clone + Decodable + ExtrasIndexable, K: ExtrasSliceConvertable + Eq + Hash + Clone { @@ -685,6 +743,7 @@ mod tests { assert_eq!(bc.best_block_hash(), genesis_hash.clone()); assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.block_hash(1), None); + assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); diff --git a/ethcore/src/chainfilter.rs b/ethcore/src/chainfilter.rs index 4043a1fee..dde91e18e 100644 --- a/ethcore/src/chainfilter.rs +++ b/ethcore/src/chainfilter.rs @@ -85,7 +85,7 @@ impl BloomIndex { /// Types implementing this trait should provide read access for bloom filters database. pub trait FilterDataSource { /// returns reference to log at given position if it exists - fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048>; + fn bloom_at_index(&self, index: &BloomIndex) -> Option; } /// In memory cache for blooms. @@ -110,8 +110,8 @@ impl MemoryCache { } impl FilterDataSource for MemoryCache { - fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048> { - self.blooms.get(index) + fn bloom_at_index(&self, index: &BloomIndex) -> Option { + self.blooms.get(index).cloned() } } @@ -238,7 +238,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource for level in 0..self.levels() { let bloom_index = self.bloom_index(block_number, level); let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { - Some(old_bloom) => old_bloom | bloom, + Some(old_bloom) => old_bloom | bloom.clone(), None => bloom.clone(), }; @@ -268,7 +268,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource // it hasn't been modified yet if is_new_bloom { let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { - Some(old_bloom) => old_bloom | &blooms[i], + Some(ref old_bloom) => old_bloom | &blooms[i], None => blooms[i].clone(), }; result.insert(bloom_index, new_bloom); @@ -298,7 +298,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource // filter existing ones .filter_map(|b| b) // BitOr all of them - .fold(H2048::new(), |acc, bloom| &acc | bloom); + .fold(H2048::new(), |acc, bloom| acc | bloom); reset_index = index.clone(); result.insert(index, &new_bloom | bloom); diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index b65d4ed7a..305b7767e 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -213,6 +213,12 @@ pub struct BlocksBlooms { pub blooms: [H2048; 16] } +impl BlocksBlooms { + pub fn new() -> Self { + BlocksBlooms { blooms: unsafe { ::std::mem::zeroed() }} + } +} + impl ExtrasIndexable for BlocksBlooms { fn extras_index() -> ExtrasIndex { ExtrasIndex::BlocksBlooms @@ -254,6 +260,14 @@ impl Encodable for BlocksBlooms { } } +/// Represents location of bloom in database. +pub struct BlocksBloomLocation { + /// Unique hash of BlocksBloom + pub hash: H256, + /// Index within BlocksBloom + pub index: usize +} + /// Represents address of certain transaction within block #[derive(Clone)] pub struct TransactionAddress { diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index c7d5e265f..0b234b00d 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -302,6 +302,10 @@ mod tests { fn block_hash(&self, index: BlockNumber) -> Option { self.numbers.get(&index).cloned() } + + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { + unimplemented!() + } } fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> { From b73d5283653a8bcec8558588dae005384b37b9e5 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 12 Feb 2016 02:03:04 +0100 Subject: [PATCH 003/753] bloomfilter reset_chain_head --- ethcore/src/blockchain.rs | 40 +++++++++++++++++++++----------------- ethcore/src/chainfilter.rs | 39 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 3c2fe3a37..26a8b4e98 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -522,25 +522,13 @@ impl BlockChain { }); } - // update block blooms - let blooms: Vec = receipts.iter().map(|r| r.log_bloom.clone()).collect(); - let modified_blooms = { - let filter = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels); - let bloom = blooms.iter().fold(H2048::new(), | ref acc, b | acc | b); - filter.add_bloom(&bloom, header.number() as usize) - }; - for (bloom_index, bloom) in modified_blooms.into_iter() { - let location = self.blocks_bloom_location(&bloom_index); - let mut blocks_blooms = self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new); - blocks_blooms.blooms[location.index] = bloom; - batch.put_extras(&location.hash, &blocks_blooms); - } - - batch.put_extras(&hash, &BlockLogBlooms { - blooms: blooms - }); + // save blooms (is it really required?). maybe store receipt whole instead? + //let blooms: Vec = receipts.iter().map(|r| r.log_bloom.clone()).collect(); + //batch.put_extras(&hash, &BlockLogBlooms { + //blooms: blooms + //}); // if it's not new best block, just return if !is_new_best { @@ -556,7 +544,21 @@ impl BlockChain { match route.blocks.len() { // its our parent - 1 => batch.put_extras(&header.number(), &hash), + 1 => { + + // update block blooms + let modified_blooms = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels) + .add_bloom(&header.log_bloom(), header.number() as usize); + + for (bloom_index, bloom) in modified_blooms.into_iter() { + let location = self.blocks_bloom_location(&bloom_index); + let mut blocks_blooms = self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new); + blocks_blooms.blooms[location.index] = bloom; + batch.put_extras(&location.hash, &blocks_blooms); + } + + batch.put_extras(&header.number(), &hash) + }, // it is a fork i if i > 1 => { let ancestor_number = self.block_number(&route.ancestor).unwrap(); @@ -564,6 +566,8 @@ impl BlockChain { for (index, hash) in route.blocks.iter().skip(route.index).enumerate() { batch.put_extras(&(start_number + index as BlockNumber), hash); } + + // TODO: replace blooms from start_number to current }, // route.blocks.len() could be 0 only if inserted block is best block, // and this is not possible at this stage diff --git a/ethcore/src/chainfilter.rs b/ethcore/src/chainfilter.rs index dde91e18e..95bac64e3 100644 --- a/ethcore/src/chainfilter.rs +++ b/ethcore/src/chainfilter.rs @@ -307,6 +307,45 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource result } + /// Resets blooms at level 0 and forces rebuild on higher levels. + pub fn reset_chain_head(&self, blooms: &[H2048], block_number: usize, old_highest_block: usize) -> HashMap { + let mut result: HashMap = HashMap::new(); + + // insert all new blooms at level 0 + for (i, bloom) in blooms.iter().enumerate() { + result.insert(self.bloom_index(block_number + i, 0), bloom.clone()); + } + + // reset the rest of blooms + for reset_number in block_number + blooms.len()..old_highest_block { + result.insert(self.bloom_index(reset_number, 0), H2048::new()); + } + + for level in 1..self.levels() { + for i in 0..blooms.len() { + + let index = self.bloom_index(block_number + i, level); + let new_bloom = { + // use new blooms before db blooms where necessary + let bloom_at = | index | { result.get(&index).cloned().or_else(|| self.data_source.bloom_at_index(&index)) }; + + self.lower_level_bloom_indexes(&index) + .into_iter() + // get blooms + .map(bloom_at) + // filter existing ones + .filter_map(|b| b) + // BitOr all of them + .fold(H2048::new(), |acc, bloom| acc | bloom) + }; + + result.insert(index, new_bloom); + } + } + + result + } + /// Sets lowest level bloom to 0 and forces rebuild on higher levels. pub fn clear_bloom(&self, block_number: usize) -> HashMap { self.reset_bloom(&H2048::new(), block_number) From 09b65037957df851400ba626a9892b8645a853ea Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 12 Feb 2016 09:52:32 +0100 Subject: [PATCH 004/753] Discovery packets --- util/src/network/connection.rs | 5 + util/src/network/discovery.rs | 201 ++++++++++++++++++++++++++------- util/src/network/error.rs | 7 ++ util/src/network/handshake.rs | 10 ++ util/src/network/host.rs | 98 ++++++++++------ util/src/network/mod.rs | 1 + util/src/network/node_table.rs | 52 +++++++++ util/src/network/session.rs | 5 + 8 files changed, 303 insertions(+), 76 deletions(-) create mode 100644 util/src/network/node_table.rs diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 746c745c4..44d429164 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -159,6 +159,11 @@ impl Connection { } } + /// Get socket token + pub fn token(&self) -> StreamToken { + self.token + } + /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "net", "connection register; token={:?}", reg); diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 32370b88d..da81920ff 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -14,26 +14,34 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -// This module is a work in progress - -#![allow(dead_code)] //TODO: remove this after everything is done - -use std::collections::{HashSet, BTreeMap}; +use bytes::Bytes; +use std::net::SocketAddr; +use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; use std::cell::{RefCell}; use std::ops::{DerefMut}; +use std::mem; use mio::*; use mio::udp::*; use hash::*; use sha3::Hashable; use crypto::*; +use rlp::*; use network::node::*; +use network::error::NetworkError; +use io::StreamToken; -const ADDRESS_BYTES_SIZE: u32 = 32; ///< Size of address type in bytes. -const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; ///< Denoted by n in [Kademlia]. -const NODE_BINS: u32 = ADDRESS_BITS - 1; ///< Size of m_state (excludes root, which is us). -const DISCOVERY_MAX_STEPS: u16 = 8; ///< Max iterations of discovery. (discover) -const BUCKET_SIZE: u32 = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket. -const ALPHA: usize = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. +const ADDRESS_BYTES_SIZE: u32 = 32; // Size of address type in bytes. +const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademlia]. +const NODE_BINS: u32 = ADDRESS_BITS - 1; // Size of m_state (excludes root, which is us). +const DISCOVERY_MAX_STEPS: u16 = 8; // Max iterations of discovery. (discover) +const BUCKET_SIZE: u32 = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. +const ALPHA: usize = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. +const MAX_DATAGRAM_SIZE: usize = 1280; + +const PACKET_PING: u8 = 1; +const PACKET_PONG: u8 = 2; +const PACKET_FIND_NODE: u8 = 3; +const PACKET_NEIGHBOURS: u8 = 4; struct NodeBucket { distance: u32, @@ -49,12 +57,25 @@ impl NodeBucket { } } -struct Discovery { +struct Datagramm { + payload: Bytes, + address: SocketAddr, +} + +pub struct Discovery { id: NodeId, + udp_socket: UdpSocket, + token: StreamToken, discovery_round: u16, discovery_id: NodeId, discovery_nodes: HashSet, node_buckets: Vec, + send_queue: VecDeque +} + +pub struct TableUpdates { + pub added: HashMap, + pub removed: HashSet, } struct FindNodePacket; @@ -72,13 +93,17 @@ impl FindNodePacket { } impl Discovery { - pub fn new(id: &NodeId) -> Discovery { + pub fn new(id: &NodeId, address: &SocketAddr, token: StreamToken) -> Discovery { + let socket = UdpSocket::bound(address).expect("Error binding UDP socket"); Discovery { id: id.clone(), + token: token, discovery_round: 0, discovery_id: NodeId::new(), discovery_nodes: HashSet::new(), node_buckets: (0..NODE_BINS).map(NodeBucket::new).collect(), + udp_socket: socket, + send_queue: VecDeque::new(), } } @@ -151,17 +176,13 @@ impl Discovery { // if d is 0, then we roll look forward, if last, we reverse, else, spread from d if head > 1 && tail != LAST_BIN { - while head != tail && head < NODE_BINS && count < BUCKET_SIZE - { - for n in &buckets[head as usize].nodes - { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { - break; - } + while head != tail && head < NODE_BINS && count < BUCKET_SIZE { + for n in &buckets[head as usize].nodes { + if count < BUCKET_SIZE { + count += 1; + found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); + } + else { break } } if count < BUCKET_SIZE && tail != 0 { for n in &buckets[tail as usize].nodes { @@ -169,9 +190,7 @@ impl Discovery { count += 1; found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); } - else { - break; - } + else { break } } } @@ -184,13 +203,11 @@ impl Discovery { else if head < 2 { while head < NODE_BINS && count < BUCKET_SIZE { for n in &buckets[head as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { - break; - } + if count < BUCKET_SIZE { + count += 1; + found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); + } + else { break } } head += 1; } @@ -198,13 +215,11 @@ impl Discovery { else { while tail > 0 && count < BUCKET_SIZE { for n in &buckets[tail as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { - break; - } + if count < BUCKET_SIZE { + count += 1; + found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); + } + else { break } } tail -= 1; } @@ -220,4 +235,108 @@ impl Discovery { } ret } + + pub fn writable(&mut self) { + if self.send_queue.is_empty() { + return; + } + let data = self.send_queue.pop_front().unwrap(); + match self.udp_socket.send_to(&data.payload, &data.address) { + Ok(Some(size)) if size == data.payload.len() => { + }, + Ok(Some(size)) => { + warn!("UDP sent incomplete datagramm"); + }, + Ok(None) => { + self.send_queue.push_front(data); + } + Err(e) => { + warn!("UDP sent error: {:?}", e); + } + } + } + + fn send_to(&mut self, payload: Bytes, address: SocketAddr) { + self.send_queue.push_back(Datagramm { payload: payload, address: address }); + } + + pub fn readable(&mut self) -> Option { + let mut buf: [u8; MAX_DATAGRAM_SIZE] = unsafe { mem::uninitialized() }; + match self.udp_socket.recv_from(&mut buf) { + Ok(Some((len, address))) => self.on_packet(&buf[0..len], address).unwrap_or_else(|e| { + debug!("Error processing UDP packet: {:?}", e); + None + }), + Ok(_) => None, + Err(e) => { + warn!("Error reading UPD socket: {:?}", e); + None + } + } + } + + fn on_packet(&mut self, packet: &[u8], from: SocketAddr) -> Result, NetworkError> { + // validate packet + if packet.len() < 32 + 65 + 4 + 1 { + return Err(NetworkError::BadProtocol); + } + + let hash_signed = (&packet[32..]).sha3(); + if hash_signed[..] != packet[0..32] { + return Err(NetworkError::BadProtocol); + } + + let signed = &packet[(32 + 65)..]; + let signature = Signature::from_slice(&packet[32..(32 + 65)]); + let node_id = try!(ec::recover(&signature, &signed.sha3())); + + let packet_id = signed[0]; + let rlp = UntrustedRlp::new(&signed[1..]); + match packet_id { + PACKET_PING => self.on_ping(&rlp, &node_id, &from), + PACKET_PONG => self.on_pong(&rlp, &node_id, &from), + PACKET_FIND_NODE => self.on_find_node(&rlp, &node_id, &from), + PACKET_NEIGHBOURS => self.on_neighbours(&rlp, &node_id, &from), + _ => { + debug!("Unknown UDP packet: {}", packet_id); + Ok(None) + } + } + } + + fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + Ok(None) + } + + fn on_pong(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + Ok(None) + } + + fn on_find_node(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + Ok(None) + } + + fn on_neighbours(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + Ok(None) + } + + pub fn round(&mut self) { + } + + pub fn refresh(&mut self) { + } + + pub fn register_socket(&self, event_loop: &mut EventLoop) -> Result<(), NetworkError> { + event_loop.register(&self.udp_socket, Token(self.token), EventSet::all(), PollOpt::edge()).expect("Error registering UDP socket"); + Ok(()) + } + + pub fn update_registration(&self, event_loop: &mut EventLoop) -> Result<(), NetworkError> { + let mut registration = EventSet::readable(); + if !self.send_queue.is_empty() { + registration &= EventSet::writable(); + } + event_loop.reregister(&self.udp_socket, Token(self.token), registration, PollOpt::edge()).expect("Error reregistering UDP socket"); + Ok(()) + } } diff --git a/util/src/network/error.rs b/util/src/network/error.rs index 4d7fb483e..eb97e54b6 100644 --- a/util/src/network/error.rs +++ b/util/src/network/error.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use io::IoError; +use crypto::CryptoError; use rlp::*; #[derive(Debug, Copy, Clone)] @@ -61,3 +62,9 @@ impl From for NetworkError { } } +impl From for NetworkError { + fn from(_err: CryptoError) -> NetworkError { + NetworkError::Auth + } +} + diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 4b23c4e16..94650b2a7 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -87,6 +87,16 @@ impl Handshake { }) } + /// Get id of the remote node if known + pub fn id(&self) -> &NodeId { + &self.id + } + + /// Get stream token id + pub fn token(&self) -> StreamToken { + self.connection.token() + } + /// Start a handhsake pub fn start(&mut self, io: &IoContext, host: &HostInfo, originated: bool) -> Result<(), UtilError> where Message: Send + Clone{ self.originated = originated; diff --git a/util/src/network/host.rs b/util/src/network/host.rs index c1423dbb3..2ad949642 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -22,7 +22,6 @@ use std::sync::*; use std::ops::*; use mio::*; use mio::tcp::*; -use mio::udp::*; use target_info::Target; use hash::*; use crypto::*; @@ -37,6 +36,8 @@ use network::node::*; use network::stats::NetworkStats; use network::error::DisconnectReason; use igd::{PortMappingProtocol,search_gateway}; +use network::discovery::{Discovery, TableUpdates}; +use network::node_table::NodeTable; type Slab = ::slab::Slab; @@ -50,6 +51,8 @@ const MAINTENANCE_TIMEOUT: u64 = 1000; #[derive(Debug)] /// Network service configuration pub struct NetworkConfiguration { + /// Directory path to store network configuration. None means nothing will be saved + pub config_path: Option, /// IP address to listen for incoming connections pub listen_address: SocketAddr, /// IP address to advertise @@ -70,6 +73,7 @@ impl NetworkConfiguration { /// Create a new instance of default settings. pub fn new() -> NetworkConfiguration { NetworkConfiguration { + config_path: None, listen_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), public_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), nat_enabled: true, @@ -114,6 +118,7 @@ impl NetworkConfiguration { } NetworkConfiguration { + config_path: self.config_path, listen_address: listen, public_address: public, nat_enabled: false, @@ -126,14 +131,12 @@ impl NetworkConfiguration { } // Tokens -//const TOKEN_BEGIN: usize = USER_TOKEN_START; // TODO: ICE in rustc 1.7.0-nightly (49c382779 2016-01-12) -const TOKEN_BEGIN: usize = 32; -const TCP_ACCEPT: usize = TOKEN_BEGIN + 1; -const IDLE: usize = TOKEN_BEGIN + 2; -const NODETABLE_RECEIVE: usize = TOKEN_BEGIN + 3; -const NODETABLE_MAINTAIN: usize = TOKEN_BEGIN + 4; -const NODETABLE_DISCOVERY: usize = TOKEN_BEGIN + 5; -const FIRST_CONNECTION: usize = TOKEN_BEGIN + 16; +const TCP_ACCEPT: usize = MAX_CONNECTIONS + 1; +const IDLE: usize = MAX_CONNECTIONS + 2; +const DISCOVERY: usize = MAX_CONNECTIONS + 3; +const DISCOVERY_REFRESH: usize = MAX_CONNECTIONS + 4; +const DISCOVERY_ROUND: usize = MAX_CONNECTIONS + 5; +const FIRST_CONNECTION: usize = 0; const LAST_CONNECTION: usize = FIRST_CONNECTION + MAX_CONNECTIONS - 1; /// Protocol handler level packet id @@ -320,10 +323,10 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, - udp_socket: Mutex, tcp_listener: Mutex, connections: Arc>>, - nodes: RwLock>, + discovery: Mutex, + nodes: RwLock, handlers: RwLock>>>, timers: RwLock>, timer_counter: RwLock, @@ -338,10 +341,12 @@ impl Host where Message: Send + Sync + Clone { let addr = config.listen_address; // Setup the server socket let tcp_listener = TcpListener::bind(&addr).unwrap(); - let udp_socket = UdpSocket::bound(&addr).unwrap(); + let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() }; + let public = keys.public().clone(); + let path = config.config_path.clone(); let mut host = Host:: { info: RwLock::new(HostInfo { - keys: if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() }, + keys: keys, config: config, nonce: H256::random(), protocol_version: 4, @@ -349,10 +354,10 @@ impl Host where Message: Send + Sync + Clone { listen_port: 0, capabilities: Vec::new(), }), - udp_socket: Mutex::new(udp_socket), + discovery: Mutex::new(Discovery::new(&public, &addr, DISCOVERY)), tcp_listener: Mutex::new(tcp_listener), connections: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS))), - nodes: RwLock::new(HashMap::new()), + nodes: RwLock::new(NodeTable::new(path)), handlers: RwLock::new(HashMap::new()), timers: RwLock::new(HashMap::new()), timer_counter: RwLock::new(LAST_CONNECTION + 1), @@ -361,12 +366,6 @@ impl Host where Message: Send + Sync + Clone { let port = host.info.read().unwrap().config.listen_address.port(); host.info.write().unwrap().deref_mut().listen_port = port; - /* - match ::ifaces::Interface::get_all().unwrap().into_iter().filter(|x| x.kind == ::ifaces::Kind::Packet && x.addr.is_some()).next() { - Some(iface) => config.public_address = iface.addr.unwrap(), - None => warn!("No public network interface"), - */ - let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); for n in boot_nodes { host.add_node(&n); @@ -382,7 +381,7 @@ impl Host where Message: Send + Sync + Clone { match Node::from_str(id) { Err(e) => { warn!("Could not add node: {:?}", e); }, Ok(n) => { - self.nodes.write().unwrap().insert(n.id.clone(), n); + self.nodes.write().unwrap().add_node(n); } } } @@ -430,12 +429,9 @@ impl Host where Message: Send + Sync + Clone { } let mut to_connect: Vec = Vec::new(); - let mut req_conn = 0; - //TODO: use nodes from discovery here - //for n in self.node_buckets.iter().flat_map(|n| &n.nodes).map(|id| NodeInfo { id: id.clone(), peer_type: self.nodes.get(id).unwrap().peer_type}) { let pin = self.info.read().unwrap().deref().config.pin; - for n in self.nodes.read().unwrap().values().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) { + for n in self.nodes.read().unwrap().nodes().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) { let connected = self.have_session(&n.id) || self.connecting_to(&n.id); let required = n.peer_type == PeerType::Required; if connected && required { @@ -685,15 +681,39 @@ impl Host where Message: Send + Sync + Clone { h.disconnected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token); } } + + fn update_nodes(&self, io: &IoContext>, node_changes: TableUpdates) { + let connections = self.connections.write().unwrap(); + let mut to_remove: Vec = Vec::new(); + for c in connections.iter() { + match *c.lock().unwrap().deref_mut() { + ConnectionEntry::Handshake(ref h) => { + if node_changes.removed.contains(&h.id) { + to_remove.push(h.token()); + } + } + ConnectionEntry::Session(ref s) => { + if node_changes.removed.contains(&s.id()) { + to_remove.push(s.token()); + } + } + } + } + for i in to_remove { + self.kill_connection(i, io); + } + self.nodes.write().unwrap().update(node_changes); + } } impl IoHandler> for Host where Message: Send + Sync + Clone + 'static { /// Initialize networking fn initialize(&self, io: &IoContext>) { io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); - io.register_stream(NODETABLE_RECEIVE).expect("Error registering UDP listener"); + io.register_stream(DISCOVERY).expect("Error registering UDP listener"); io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer"); - //io.register_timer(NODETABLE_MAINTAIN, 7200); + io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); + io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); } fn stream_hup(&self, io: &IoContext>, stream: StreamToken) { @@ -707,7 +727,11 @@ impl IoHandler> for Host where Messa fn stream_readable(&self, io: &IoContext>, stream: StreamToken) { match stream { FIRST_CONNECTION ... LAST_CONNECTION => self.connection_readable(stream, io), - NODETABLE_RECEIVE => {}, + DISCOVERY => { + if let Some(node_changes) = self.discovery.lock().unwrap().readable() { + self.update_nodes(io, node_changes); + } + }, TCP_ACCEPT => self.accept(io), _ => panic!("Received unknown readable token"), } @@ -716,7 +740,7 @@ impl IoHandler> for Host where Messa fn stream_writable(&self, io: &IoContext>, stream: StreamToken) { match stream { FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io), - NODETABLE_RECEIVE => {}, + DISCOVERY => self.discovery.lock().unwrap().writable(), _ => panic!("Received unknown writable token"), } } @@ -725,8 +749,12 @@ impl IoHandler> for Host where Messa match token { IDLE => self.maintain_network(io), FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io), - NODETABLE_DISCOVERY => {}, - NODETABLE_MAINTAIN => {}, + DISCOVERY_REFRESH => { + self.discovery.lock().unwrap().refresh(); + }, + DISCOVERY_ROUND => { + self.discovery.lock().unwrap().round(); + }, _ => match self.timers.read().unwrap().get(&token).cloned() { Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() { None => { warn!(target: "net", "No handler found for protocol: {:?}", timer.protocol) }, @@ -794,7 +822,7 @@ impl IoHandler> for Host where Messa } } else {} // expired } - NODETABLE_RECEIVE => event_loop.register(self.udp_socket.lock().unwrap().deref(), Token(NODETABLE_RECEIVE), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), + DISCOVERY => self.discovery.lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } @@ -812,7 +840,7 @@ impl IoHandler> for Host where Messa connections.remove(stream); } }, - NODETABLE_RECEIVE => event_loop.deregister(self.udp_socket.lock().unwrap().deref()).unwrap(), + DISCOVERY => (), TCP_ACCEPT => event_loop.deregister(self.tcp_listener.lock().unwrap().deref()).unwrap(), _ => warn!("Unexpected stream deregistration") } @@ -828,7 +856,7 @@ impl IoHandler> for Host where Messa } } else {} // expired } - NODETABLE_RECEIVE => event_loop.reregister(self.udp_socket.lock().unwrap().deref(), Token(NODETABLE_RECEIVE), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), + DISCOVERY => self.discovery.lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index 6b58c87eb..e5465c952 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -72,6 +72,7 @@ mod discovery; mod service; mod error; mod node; +mod node_table; mod stats; #[cfg(test)] diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs new file mode 100644 index 000000000..0f1c2c5ad --- /dev/null +++ b/util/src/network/node_table.rs @@ -0,0 +1,52 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashMap; +use std::collections::hash_map::Values; +use network::node::*; +use network::discovery::TableUpdates; + +pub struct NodeTable { + nodes: HashMap +} + +impl NodeTable { + pub fn new(_path: Option) -> NodeTable { + NodeTable { + nodes: HashMap::new() + } + } + + pub fn add_node(&mut self, node: Node) { + self.nodes.insert(node.id.clone(), node); + } + + pub fn nodes(&self) -> Values { + self.nodes.values() + } + + pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> { + self.nodes.get_mut(id) + } + + pub fn update(&mut self, mut update: TableUpdates) { + self.nodes.extend(update.added.drain()); + for r in update.removed { + self.nodes.remove(&r); + } + } + +} diff --git a/util/src/network/session.rs b/util/src/network/session.rs index b38807c49..19e2cf08e 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -129,6 +129,11 @@ impl Session { Ok(session) } + /// Get id of the remote peer + pub fn id(&self) -> &NodeId { + &self.info.id + } + /// Check if session is ready to send/receive data pub fn is_ready(&self) -> bool { self.had_hello From c9e0071fdef387fd5c837501721c991a98870c7c Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 12 Feb 2016 14:03:23 +0100 Subject: [PATCH 005/753] blockchain bloomfilter should be ok by now... --- ethcore/src/blockchain.rs | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 26a8b4e98..ef6090a53 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -542,22 +542,16 @@ impl BlockChain { let best_details = self.block_details(&best_hash).expect("best block hash is invalid!"); let route = self.tree_route_aux((&best_details, &best_hash), (&details, &hash)); + let modified_blooms; + match route.blocks.len() { // its our parent 1 => { + batch.put_extras(&header.number(), &hash); // update block blooms - let modified_blooms = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels) + modified_blooms = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels) .add_bloom(&header.log_bloom(), header.number() as usize); - - for (bloom_index, bloom) in modified_blooms.into_iter() { - let location = self.blocks_bloom_location(&bloom_index); - let mut blocks_blooms = self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new); - blocks_blooms.blooms[location.index] = bloom; - batch.put_extras(&location.hash, &blocks_blooms); - } - - batch.put_extras(&header.number(), &hash) }, // it is a fork i if i > 1 => { @@ -567,13 +561,34 @@ impl BlockChain { batch.put_extras(&(start_number + index as BlockNumber), hash); } - // TODO: replace blooms from start_number to current + // get all blocks that are not part of canon chain (TODO: optimize it to one query) + let blooms: Vec = route.blocks.iter() + .skip(route.index) + .map(|hash| self.block(hash).unwrap()) + .map(|bytes| BlockView::new(&bytes).header_view().log_bloom()) + .collect(); + + // reset blooms chain head + modified_blooms = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels) + .reset_chain_head(&blooms, start_number as usize, self.best_block_number() as usize); }, // route.blocks.len() could be 0 only if inserted block is best block, // and this is not possible at this stage _ => { unreachable!(); } }; + for (hash, blocks_blooms) in modified_blooms.into_iter() + .fold(HashMap::new(), | mut acc, (bloom_index, bloom) | { + { + let location = self.blocks_bloom_location(&bloom_index); + let mut blocks_blooms = acc.entry(location.hash).or_insert_with(BlocksBlooms::new); + blocks_blooms.blooms[location.index] = bloom; + } + acc + }) { + batch.put_extras(&hash, &blocks_blooms); + } + // this is new best block batch.put(b"best", &hash).unwrap(); From 3fcade9f6d9fef6bc024d31bb17dc9ff371773f4 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 13 Feb 2016 13:05:28 +0100 Subject: [PATCH 006/753] bloom possibilities in progress --- ethcore/src/client.rs | 19 +++++++++ rpc/src/v1/types/filter.rs | 79 ++++++++++++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index d9e461024..c7a5ec268 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -144,6 +144,9 @@ pub trait BlockChainClient : Sync + Send { fn best_block_header(&self) -> Bytes { self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option>; } #[derive(Default, Clone, Debug, Eq, PartialEq)] @@ -358,6 +361,15 @@ impl Client { BlockId::Latest => Some(self.chain.read().unwrap().best_block_hash()) } } + + fn block_number(&self, id: BlockId) -> Option { + match id { + BlockId::Number(number) => Some(number), + BlockId::Hash(ref hash) => self.chain.read().unwrap().block_number(hash), + BlockId::Earliest => Some(0), + BlockId::Latest => Some(self.chain.read().unwrap().best_block_number()) + } + } } impl BlockChainClient for Client { @@ -450,6 +462,13 @@ impl BlockChainClient for Client { best_block_number: From::from(chain.best_block_number()) } } + + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option> { + match (self.block_number(from_block), self.block_number(to_block)) { + (Some(from), Some(to)) => Some(self.chain.read().unwrap().blocks_with_bloom(bloom, from, to)), + _ => None + } + } } impl MayPanic for Client { diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index 9b21cf8e7..cac1f7ef9 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -18,40 +18,95 @@ use serde::{Deserialize, Deserializer, Error}; use serde_json::value; use jsonrpc_core::Value; use util::hash::*; +use util::sha3::*; use v1::types::BlockNumber; #[derive(Debug, PartialEq)] -pub enum Topic { - Single(H256), - Multiple(Vec), +pub enum VariadicValue where T: Deserialize { + Single(T), + Multiple(Vec), Null } -impl Deserialize for Topic { - fn deserialize(deserializer: &mut D) -> Result +impl Deserialize for VariadicValue where T: Deserialize { + fn deserialize(deserializer: &mut D) -> Result, D::Error> where D: Deserializer { let v = try!(Value::deserialize(deserializer)); if v.is_null() { - return Ok(Topic::Null); + return Ok(VariadicValue::Null); } - Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Single) - .or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Multiple)) + Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Single) + .or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Multiple)) .map_err(|_| Error::syntax("")) // unreachable, but types must match } } +pub type FilterAddress = VariadicValue
; +pub type Topic = VariadicValue; + #[derive(Debug, PartialEq, Deserialize)] pub struct Filter { #[serde(rename="fromBlock")] pub from_block: Option, #[serde(rename="toBlock")] pub to_block: Option, - pub address: Option
, + pub address: Option, pub topics: Option> } +impl Filter { + /// Returns combinations of each of address topic. + pub fn bloom_possibilities(&self) -> Vec { + let blooms = match self.address { + Some(VariadicValue::Single(ref address)) => { + let mut bloom = H2048::new(); + bloom.shift_bloomed(&address.sha3()); + vec![bloom] + }, + Some(VariadicValue::Multiple(ref addresses)) => { + addresses.iter().map(|ref address| { + let mut bloom = H2048::new(); + bloom.shift_bloomed(&address.sha3()); + bloom + }).collect() + }, + _ => vec![H2048::new()] + }; + + match self.topics { + None => blooms, + Some(ref topics) => blooms.into_iter().map(|bloom| { + //for topic in topics { + //match topic { + //VariadicValue::Single => { + //bloom.shift_bloomed(&topic.sha3()); + //bloom + //} + //} + //} + }).collect() + } + //self.address.as_ref().map(|a| match *a { + //VariadicValue::Single(ref address) => { + //let mut bloom = H2048::new(); + //bloom.shift_bloomed(&address.sha3()); + //vec![bloom] + //}, + //VariadicValue::Multiple(ref addresses) => { + //addresses.iter().map(|ref address| { + //let mut bloom = H2048::new(); + //bloom.shift_bloomed(&address.sha3()); + //bloom + //}).collect() + //}, + //VariadicValue::Null => vec![H2048::new()] + //}.into_iter().map(|bloom| match self. { + //}).unwrap_or_else(Vec::new) + } +} + #[cfg(test)] mod tests { use serde_json; @@ -65,9 +120,9 @@ mod tests { let s = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]"#; let deserialized: Vec = serde_json::from_str(s).unwrap(); assert_eq!(deserialized, vec![ - Topic::Single(H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()), - Topic::Null, - Topic::Multiple(vec![ + VariadicValue::Single(H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()), + VariadicValue::Null, + VariadicValue::Multiple(vec![ H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(), H256::from_str("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc").unwrap() ]) From 62b9f4b91db181f0d93ee1d76e78dbd526f82e25 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 13 Feb 2016 22:57:39 +0100 Subject: [PATCH 007/753] UDP discovery working --- util/src/bytes.rs | 24 +- util/src/hash.rs | 6 - util/src/lib.rs | 1 + util/src/network/discovery.rs | 394 ++++++++++++++++++++++----------- util/src/network/error.rs | 2 + util/src/network/host.rs | 43 ++-- util/src/network/mod.rs | 2 + util/src/network/node.rs | 78 ++++++- util/src/network/node_table.rs | 5 +- 9 files changed, 375 insertions(+), 180 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 5ad2660e8..4923e6eb4 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -170,28 +170,8 @@ pub trait BytesConvertable { fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() } } -impl<'a> BytesConvertable for &'a [u8] { - fn bytes(&self) -> &[u8] { self } -} - -impl BytesConvertable for Vec { - fn bytes(&self) -> &[u8] { self } -} - -macro_rules! impl_bytes_convertable_for_array { - ($zero: expr) => (); - ($len: expr, $($idx: expr),*) => { - impl BytesConvertable for [u8; $len] { - fn bytes(&self) -> &[u8] { self } - } - impl_bytes_convertable_for_array! { $($idx),* } - } -} - -// -1 at the end is not expanded -impl_bytes_convertable_for_array! { - 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1 +impl BytesConvertable for T where T: Deref { + fn bytes(&self) -> &[u8] { self.deref() } } #[test] diff --git a/util/src/hash.rs b/util/src/hash.rs index 75c39720e..c678d13a7 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -77,12 +77,6 @@ macro_rules! impl_hash { /// Unformatted binary data of fixed length. pub struct $from (pub [u8; $size]); - impl BytesConvertable for $from { - fn bytes(&self) -> &[u8] { - &self.0 - } - } - impl Deref for $from { type Target = [u8]; diff --git a/util/src/lib.rs b/util/src/lib.rs index bdd595014..05162bca7 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -19,6 +19,7 @@ #![feature(augmented_assignments)] #![feature(associated_consts)] #![feature(plugin)] +#![feature(ip)] #![plugin(clippy)] #![allow(needless_range_loop, match_bool)] #![feature(catch_panic)] diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index da81920ff..a214f5278 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -17,24 +17,26 @@ use bytes::Bytes; use std::net::SocketAddr; use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; -use std::cell::{RefCell}; -use std::ops::{DerefMut}; use std::mem; +use std::cmp; use mio::*; use mio::udp::*; +use sha3::*; +use time; use hash::*; -use sha3::Hashable; use crypto::*; use rlp::*; use network::node::*; use network::error::NetworkError; use io::StreamToken; +use network::PROTOCOL_VERSION; + const ADDRESS_BYTES_SIZE: u32 = 32; // Size of address type in bytes. const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademlia]. const NODE_BINS: u32 = ADDRESS_BITS - 1; // Size of m_state (excludes root, which is us). const DISCOVERY_MAX_STEPS: u16 = 8; // Max iterations of discovery. (discover) -const BUCKET_SIZE: u32 = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. +const BUCKET_SIZE: usize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. const ALPHA: usize = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. const MAX_DATAGRAM_SIZE: usize = 1280; @@ -43,16 +45,27 @@ const PACKET_PONG: u8 = 2; const PACKET_FIND_NODE: u8 = 3; const PACKET_NEIGHBOURS: u8 = 4; +const PING_TIMEOUT_MS: u64 = 300; + +#[derive(Clone, Debug)] +pub struct NodeEntry { + pub id: NodeId, + pub endpoint: NodeEndpoint, +} + +pub struct BucketEntry { + pub address: NodeEntry, + pub timeout: Option, +} + struct NodeBucket { - distance: u32, - nodes: Vec + nodes: VecDeque, //sorted by last active } impl NodeBucket { - fn new(distance: u32) -> NodeBucket { + fn new() -> NodeBucket { NodeBucket { - distance: distance, - nodes: Vec::new() + nodes: VecDeque::new() } } } @@ -64,6 +77,8 @@ struct Datagramm { pub struct Discovery { id: NodeId, + secret: Secret, + address: NodeEndpoint, udp_socket: UdpSocket, token: StreamToken, discovery_round: u16, @@ -74,80 +89,90 @@ pub struct Discovery { } pub struct TableUpdates { - pub added: HashMap, + pub added: HashMap, pub removed: HashSet, } -struct FindNodePacket; - -impl FindNodePacket { - fn new(_endpoint: &NodeEndpoint, _id: &NodeId) -> FindNodePacket { - FindNodePacket - } - - fn sign(&mut self, _secret: &Secret) { - } - - fn send(& self, _socket: &mut UdpSocket) { - } -} - impl Discovery { - pub fn new(id: &NodeId, address: &SocketAddr, token: StreamToken) -> Discovery { - let socket = UdpSocket::bound(address).expect("Error binding UDP socket"); + pub fn new(key: &KeyPair, address: NodeEndpoint, token: StreamToken) -> Discovery { + let socket = UdpSocket::bound(&address.udp_address()).expect("Error binding UDP socket"); Discovery { - id: id.clone(), + id: key.public().clone(), + secret: key.secret().clone(), + address: address, token: token, discovery_round: 0, discovery_id: NodeId::new(), discovery_nodes: HashSet::new(), - node_buckets: (0..NODE_BINS).map(NodeBucket::new).collect(), + node_buckets: (0..NODE_BINS).map(|_| NodeBucket::new()).collect(), udp_socket: socket, send_queue: VecDeque::new(), } } - pub fn add_node(&mut self, id: &NodeId) { - self.node_buckets[Discovery::distance(&self.id, &id) as usize].nodes.push(id.clone()); + pub fn add_node(&mut self, e: NodeEntry) { + let endpoint = e.endpoint.clone(); + self.update_node(e); + self.ping(&endpoint); } - fn start_node_discovery(&mut self, event_loop: &mut EventLoop) { + fn update_node(&mut self, e: NodeEntry) { + trace!(target: "discovery", "Inserting {:?}", &e); + let ping = { + let mut bucket = self.node_buckets.get_mut(Discovery::distance(&self.id, &e.id) as usize).unwrap(); + let updated = if let Some(node) = bucket.nodes.iter_mut().find(|n| n.address.id == e.id) { + node.address = e.clone(); + node.timeout = None; + true + } else { false }; + + if !updated { + bucket.nodes.push_front(BucketEntry { address: e, timeout: None }); + } + + if bucket.nodes.len() > BUCKET_SIZE { + //ping least active node + bucket.nodes.back_mut().unwrap().timeout = Some(time::precise_time_ns()); + Some(bucket.nodes.back().unwrap().address.endpoint.clone()) + } else { None } + }; + if let Some(endpoint) = ping { + self.ping(&endpoint); + } + } + + fn start(&mut self) { + trace!(target: "discovery", "Starting discovery"); self.discovery_round = 0; - self.discovery_id.randomize(); + self.discovery_id.randomize(); //TODO: use cryptographic nonce self.discovery_nodes.clear(); - self.discover(event_loop); } - fn discover(&mut self, event_loop: &mut EventLoop) { - if self.discovery_round == DISCOVERY_MAX_STEPS - { - debug!("Restarting discovery"); - self.start_node_discovery(event_loop); + fn discover(&mut self) { + if self.discovery_round == DISCOVERY_MAX_STEPS { return; } + trace!(target: "discovery", "Starting round {:?}", self.discovery_round); let mut tried_count = 0; { - let nearest = Discovery::nearest_node_entries(&self.id, &self.discovery_id, &self.node_buckets).into_iter(); - let nodes = RefCell::new(&mut self.discovery_nodes); - let nearest = nearest.filter(|x| nodes.borrow().contains(&x)).take(ALPHA); + let nearest = Discovery::nearest_node_entries(&self.discovery_id, &self.node_buckets).into_iter(); + let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::>(); for r in nearest { - //let mut p = FindNodePacket::new(&r.endpoint, &self.discovery_id); - //p.sign(&self.secret); - //p.send(&mut self.udp_socket); - let mut borrowed = nodes.borrow_mut(); - borrowed.deref_mut().insert(r.clone()); + let rlp = encode(&(&[self.discovery_id.clone()][..])); + self.send_packet(PACKET_FIND_NODE, &r.endpoint.udp_address(), &rlp); + self.discovery_nodes.insert(r.id.clone()); tried_count += 1; + trace!(target: "discovery", "Sent FindNode to {:?}", &r.endpoint); } } - if tried_count == 0 - { - debug!("Restarting discovery"); - self.start_node_discovery(event_loop); + if tried_count == 0 { + trace!(target: "discovery", "Completing discovery"); + self.discovery_round = DISCOVERY_MAX_STEPS; + self.discovery_nodes.clear(); return; } self.discovery_round += 1; - //event_loop.timeout_ms(Token(NODETABLE_DISCOVERY), 1200).unwrap(); } fn distance(a: &NodeId, b: &NodeId) -> u32 { @@ -163,75 +188,75 @@ impl Discovery { ret } - #[allow(cyclomatic_complexity)] - fn nearest_node_entries<'b>(source: &NodeId, target: &NodeId, buckets: &'b [NodeBucket]) -> Vec<&'b NodeId> - { - // send ALPHA FindNode packets to nodes we know, closest to target - const LAST_BIN: u32 = NODE_BINS - 1; - let mut head = Discovery::distance(source, target); - let mut tail = if head == 0 { LAST_BIN } else { (head - 1) % NODE_BINS }; + fn ping(&mut self, node: &NodeEndpoint) { + let mut rlp = RlpStream::new_list(3); + rlp.append(&PROTOCOL_VERSION); + self.address.to_rlp_list(&mut rlp); + node.to_rlp_list(&mut rlp); + trace!(target: "discovery", "Sent Ping to {:?}", &node); + self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain()); + } - let mut found: BTreeMap> = BTreeMap::new(); + fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) { + let mut rlp = RlpStream::new(); + rlp.append_raw(&[packet_id], 1); + let source = Rlp::new(payload); + rlp.begin_list(source.item_count() + 1); + for i in 0 .. source.item_count() { + rlp.append_raw(source.at(i).as_raw(), 1); + } + let timestamp = time::get_time().sec as u32 + 60; + rlp.append(×tamp); + + let bytes = rlp.drain(); + let hash = bytes.sha3(); + let signature = match ec::sign(&self.secret, &hash) { + Ok(s) => s, + Err(_) => { + warn!("Error signing UDP packet"); + return; + } + }; + let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65); + packet.extend(hash.iter()); + packet.extend(signature.iter()); + packet.extend(bytes.iter()); + let signed_hash = (&packet[32..]).sha3(); + packet[0..32].clone_from_slice(&signed_hash); + self.send_to(packet, address.clone()); + } + + #[allow(map_clone)] + fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec + { + let mut found: BTreeMap> = BTreeMap::new(); let mut count = 0; - // if d is 0, then we roll look forward, if last, we reverse, else, spread from d - if head > 1 && tail != LAST_BIN { - while head != tail && head < NODE_BINS && count < BUCKET_SIZE { - for n in &buckets[head as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { break } - } - if count < BUCKET_SIZE && tail != 0 { - for n in &buckets[tail as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { break } + // Sort nodes by distance to target + for bucket in buckets { + for node in &bucket.nodes { + let distance = Discovery::distance(target, &node.address.id); + found.entry(distance).or_insert_with(Vec::new).push(&node.address); + if count == BUCKET_SIZE { + // delete the most distant element + let remove = { + let (_, last) = found.iter_mut().next_back().unwrap(); + last.pop(); + last.is_empty() + }; + if remove { + found.remove(&distance); } } - - head += 1; - if tail > 0 { - tail -= 1; + else { + count += 1; } } } - else if head < 2 { - while head < NODE_BINS && count < BUCKET_SIZE { - for n in &buckets[head as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { break } - } - head += 1; - } - } - else { - while tail > 0 && count < BUCKET_SIZE { - for n in &buckets[tail as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { break } - } - tail -= 1; - } - } - let mut ret:Vec<&NodeId> = Vec::new(); + let mut ret:Vec = Vec::new(); for (_, nodes) in found { - for n in nodes { - if ret.len() < BUCKET_SIZE as usize /* && n->endpoint && n->endpoint.isAllowed() */ { - ret.push(n); - } - } + ret.extend(nodes.iter().map(|&n| n.clone())); } ret } @@ -240,18 +265,22 @@ impl Discovery { if self.send_queue.is_empty() { return; } - let data = self.send_queue.pop_front().unwrap(); - match self.udp_socket.send_to(&data.payload, &data.address) { - Ok(Some(size)) if size == data.payload.len() => { - }, - Ok(Some(size)) => { - warn!("UDP sent incomplete datagramm"); - }, - Ok(None) => { - self.send_queue.push_front(data); - } - Err(e) => { - warn!("UDP sent error: {:?}", e); + while !self.send_queue.is_empty() { + let data = self.send_queue.pop_front().unwrap(); + match self.udp_socket.send_to(&data.payload, &data.address) { + Ok(Some(size)) if size == data.payload.len() => { + }, + Ok(Some(_)) => { + warn!("UDP sent incomplete datagramm"); + }, + Ok(None) => { + self.send_queue.push_front(data); + return; + } + Err(e) => { + warn!("UDP send error: {:?}, address: {:?}", e, &data.address); + return; + } } } } @@ -305,25 +334,132 @@ impl Discovery { } fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { - Ok(None) + trace!(target: "discovery", "Got Ping from {:?}", &from); + let version: u32 = try!(rlp.val_at(0)); + if version != PROTOCOL_VERSION { + debug!(target: "discovery", "Unexpected protocol version: {}", version); + return Err(NetworkError::BadProtocol); + } + let source = try!(NodeEndpoint::from_rlp(&try!(rlp.at(1)))); + let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(2)))); + let timestamp: u64 = try!(rlp.val_at(3)); + if timestamp < time::get_time().sec as u64{ + debug!(target: "discovery", "Expired ping"); + return Err(NetworkError::Expired); + } + let mut entry = NodeEntry { id: node.clone(), endpoint: source.clone() }; + if !entry.endpoint.is_valid() { + debug!(target: "discovery", "Bad address: {:?}", entry); + entry.endpoint.address = from.clone(); + } + self.update_node(entry.clone()); + let hash = rlp.as_raw().sha3(); + let mut response = RlpStream::new_list(2); + dest.to_rlp_list(&mut response); + response.append(&hash); + self.send_packet(PACKET_PONG, &entry.endpoint.udp_address(), &response.drain()); + + let mut added_map = HashMap::new(); + added_map.insert(node.clone(), entry); + Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) } fn on_pong(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + trace!(target: "discovery", "Got Pong from {:?}", &from); + // TODO: validate pong packet + let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(0)))); + let timestamp: u64 = try!(rlp.val_at(2)); + if timestamp > time::get_time().sec as u64 { + return Err(NetworkError::Expired); + } + let mut entry = NodeEntry { id: node.clone(), endpoint: dest }; + if !entry.endpoint.is_valid() { + debug!(target: "discovery", "Bad address: {:?}", entry); + entry.endpoint.address = from.clone(); + } + self.update_node(entry.clone()); + let mut added_map = HashMap::new(); + added_map.insert(node.clone(), entry); + Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) + } + + fn on_find_node(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + trace!(target: "discovery", "Got FindNode from {:?}", &from); + let target: NodeId = try!(rlp.val_at(0)); + let timestamp: u64 = try!(rlp.val_at(1)); + if timestamp > time::get_time().sec as u64 { + return Err(NetworkError::Expired); + } + + let limit = (MAX_DATAGRAM_SIZE - 109) / 90; + let nearest = Discovery::nearest_node_entries(&target, &self.node_buckets); + if nearest.is_empty() { + return Ok(None); + } + let mut rlp = RlpStream::new_list(cmp::min(limit, nearest.len())); + rlp.begin_list(1); + for n in 0 .. nearest.len() { + rlp.begin_list(4); + nearest[n].endpoint.to_rlp(&mut rlp); + rlp.append(&nearest[n].id); + if (n + 1) % limit == 0 || n == nearest.len() - 1 { + self.send_packet(PACKET_NEIGHBOURS, &from, &rlp.drain()); + trace!(target: "discovery", "Sent {} Neighbours to {:?}", n, &from); + rlp = RlpStream::new_list(cmp::min(limit, nearest.len() - n)); + rlp.begin_list(1); + } + } Ok(None) } - fn on_find_node(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { - Ok(None) + fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + // TODO: validate packet + let mut added = HashMap::new(); + trace!(target: "discovery", "Got {} Neighbours from {:?}", try!(rlp.at(0)).item_count(), &from); + for r in try!(rlp.at(0)).iter() { + let endpoint = try!(NodeEndpoint::from_rlp(&r)); + if !endpoint.is_valid() { + debug!(target: "discovery", "Bad address: {:?}", endpoint); + continue; + } + let node_id: NodeId = try!(r.val_at(3)); + let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint }; + added.insert(node_id, entry.clone()); + self.update_node(entry); + } + Ok(Some(TableUpdates { added: added, removed: HashSet::new() })) } - fn on_neighbours(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { - Ok(None) + fn check_expired(&mut self) -> HashSet { + let now = time::precise_time_ns(); + let mut removed: HashSet = HashSet::new(); + for bucket in &mut self.node_buckets { + bucket.nodes.retain(|node| { + if let Some(timeout) = node.timeout { + if now - timeout < PING_TIMEOUT_MS * 1000_0000 { + true + } + else { + trace!(target: "discovery", "Removed expired node {:?}", &node.address); + removed.insert(node.address.id.clone()); + false + } + } else { true } + }); + } + removed } - pub fn round(&mut self) { + pub fn round(&mut self) -> Option { + let removed = self.check_expired(); + self.discover(); + if !removed.is_empty() { + Some(TableUpdates { added: HashMap::new(), removed: removed }) + } else { None } } pub fn refresh(&mut self) { + self.start(); } pub fn register_socket(&self, event_loop: &mut EventLoop) -> Result<(), NetworkError> { @@ -334,7 +470,7 @@ impl Discovery { pub fn update_registration(&self, event_loop: &mut EventLoop) -> Result<(), NetworkError> { let mut registration = EventSet::readable(); if !self.send_queue.is_empty() { - registration &= EventSet::writable(); + registration = registration | EventSet::writable(); } event_loop.reregister(&self.udp_socket, Token(self.token), registration, PollOpt::edge()).expect("Error reregistering UDP socket"); Ok(()) diff --git a/util/src/network/error.rs b/util/src/network/error.rs index eb97e54b6..74babb110 100644 --- a/util/src/network/error.rs +++ b/util/src/network/error.rs @@ -42,6 +42,8 @@ pub enum NetworkError { Auth, /// Unrecognised protocol. BadProtocol, + /// Message expired. + Expired, /// Peer not found. PeerNotFound, /// Peer is diconnected. diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 05462be37..47a3d9986 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -31,21 +31,18 @@ use network::handshake::Handshake; use network::session::{Session, SessionData}; use error::*; use io::*; -use network::NetworkProtocolHandler; +use network::{NetworkProtocolHandler, PROTOCOL_VERSION}; use network::node::*; use network::stats::NetworkStats; use network::error::DisconnectReason; use igd::{PortMappingProtocol,search_gateway}; -use network::discovery::{Discovery, TableUpdates}; +use network::discovery::{Discovery, TableUpdates, NodeEntry}; use network::node_table::NodeTable; type Slab = ::slab::Slab; const _DEFAULT_PORT: u16 = 30304; - const MAX_CONNECTIONS: usize = 1024; -const IDEAL_PEERS: u32 = 10; - const MAINTENANCE_TIMEOUT: u64 = 1000; #[derive(Debug)] @@ -67,6 +64,8 @@ pub struct NetworkConfiguration { pub boot_nodes: Vec, /// Use provided node key instead of default pub use_secret: Option, + /// Number of connected peers to maintain + pub ideal_peers: u32, } impl NetworkConfiguration { @@ -81,6 +80,7 @@ impl NetworkConfiguration { pin: false, boot_nodes: Vec::new(), use_secret: None, + ideal_peers: 10, } } @@ -126,6 +126,7 @@ impl NetworkConfiguration { pin: self.pin, boot_nodes: self.boot_nodes, use_secret: self.use_secret, + ideal_peers: self.ideal_peers, } } } @@ -343,19 +344,20 @@ impl Host where Message: Send + Sync + Clone { // Setup the server socket let tcp_listener = TcpListener::bind(&addr).unwrap(); let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() }; - let public = keys.public().clone(); + let endpoint = NodeEndpoint { address: addr.clone(), udp_port: addr.port() }; + let discovery = Discovery::new(&keys, endpoint, DISCOVERY); let path = config.config_path.clone(); let mut host = Host:: { info: RwLock::new(HostInfo { keys: keys, config: config, nonce: H256::random(), - protocol_version: 4, + protocol_version: PROTOCOL_VERSION, client_version: format!("Parity/{}/{}-{}-{}", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()), listen_port: 0, capabilities: Vec::new(), }), - discovery: Mutex::new(Discovery::new(&public, &addr, DISCOVERY)), + discovery: Mutex::new(discovery), tcp_listener: Mutex::new(tcp_listener), connections: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS))), nodes: RwLock::new(NodeTable::new(path)), @@ -382,7 +384,9 @@ impl Host where Message: Send + Sync + Clone { match Node::from_str(id) { Err(e) => { warn!("Could not add node: {:?}", e); }, Ok(n) => { + let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; self.nodes.write().unwrap().add_node(n); + self.discovery.lock().unwrap().add_node(entry); } } } @@ -432,6 +436,7 @@ impl Host where Message: Send + Sync + Clone { let mut to_connect: Vec = Vec::new(); let mut req_conn = 0; let pin = self.info.read().unwrap().deref().config.pin; + let ideal_peers = self.info.read().unwrap().deref().config.ideal_peers; for n in self.nodes.read().unwrap().nodes().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) { let connected = self.have_session(&n.id) || self.connecting_to(&n.id); let required = n.peer_type == PeerType::Required; @@ -445,7 +450,7 @@ impl Host where Message: Send + Sync + Clone { for n in &to_connect { if n.peer_type == PeerType::Required { - if req_conn < IDEAL_PEERS { + if req_conn < ideal_peers { self.connect_peer(&n.id, io); } req_conn += 1; @@ -455,7 +460,7 @@ impl Host where Message: Send + Sync + Clone { if !pin { let pending_count = 0; //TODO: let peer_count = 0; - let mut open_slots = IDEAL_PEERS - peer_count - pending_count + req_conn; + let mut open_slots = ideal_peers - peer_count - pending_count + req_conn; if open_slots > 0 { for n in &to_connect { if n.peer_type == PeerType::Optional && open_slots > 0 { @@ -471,11 +476,11 @@ impl Host where Message: Send + Sync + Clone { fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { - warn!("Aborted connect. Node already connected."); + debug!("Aborted connect. Node already connected."); return; } if self.connecting_to(id) { - warn!("Aborted connect. Node already connecting."); + debug!("Aborted connect. Node already connecting."); return; } @@ -689,7 +694,7 @@ impl Host where Message: Send + Sync + Clone { for c in connections.iter() { match *c.lock().unwrap().deref_mut() { ConnectionEntry::Handshake(ref h) => { - if node_changes.removed.contains(&h.id) { + if node_changes.removed.contains(&h.id()) { to_remove.push(h.token()); } } @@ -732,6 +737,7 @@ impl IoHandler> for Host where Messa if let Some(node_changes) = self.discovery.lock().unwrap().readable() { self.update_nodes(io, node_changes); } + io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); }, TCP_ACCEPT => self.accept(io), _ => panic!("Received unknown readable token"), @@ -741,7 +747,10 @@ impl IoHandler> for Host where Messa fn stream_writable(&self, io: &IoContext>, stream: StreamToken) { match stream { FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io), - DISCOVERY => self.discovery.lock().unwrap().writable(), + DISCOVERY => { + self.discovery.lock().unwrap().writable(); + io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); + } _ => panic!("Received unknown writable token"), } } @@ -752,9 +761,13 @@ impl IoHandler> for Host where Messa FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io), DISCOVERY_REFRESH => { self.discovery.lock().unwrap().refresh(); + io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); }, DISCOVERY_ROUND => { - self.discovery.lock().unwrap().round(); + if let Some(node_changes) = self.discovery.lock().unwrap().round() { + self.update_nodes(io, node_changes); + } + io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); }, _ => match self.timers.read().unwrap().get(&token).cloned() { Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() { diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index e5465c952..466ef4e6a 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -90,6 +90,8 @@ pub use network::stats::NetworkStats; use io::TimerToken; +const PROTOCOL_VERSION: u32 = 4; + /// Network IO protocol handler. This needs to be implemented for each new subprotocol. /// All the handler function are called from within IO event loop. /// `Message` is the type for message data. diff --git a/util/src/network/node.rs b/util/src/network/node.rs index e23dee9f5..d8370bc79 100644 --- a/util/src/network/node.rs +++ b/util/src/network/node.rs @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::net::{SocketAddr, ToSocketAddrs}; +use std::mem; +use std::slice::from_raw_parts; +use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; use std::hash::{Hash, Hasher}; use std::str::{FromStr}; use hash::*; @@ -25,17 +27,69 @@ use error::*; /// Node public key pub type NodeId = H512; -#[derive(Debug)] -/// Noe address info +#[derive(Debug, Clone)] +/// Node address info pub struct NodeEndpoint { /// IP(V4 or V6) address pub address: SocketAddr, - /// Address as string (can be host name). - pub address_str: String, /// Conneciton port. pub udp_port: u16 } +impl NodeEndpoint { + pub fn udp_address(&self) -> SocketAddr { + match self.address { + SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)), + SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())), + } + } +} + +impl NodeEndpoint { + pub fn from_rlp(rlp: &UntrustedRlp) -> Result { + let tcp_port = try!(rlp.val_at::(2)); + let udp_port = try!(rlp.val_at::(1)); + let addr_bytes = try!(try!(rlp.at(0)).data()); + let address = try!(match addr_bytes.len() { + 4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))), + 16 => unsafe { + let o: *const u16 = mem::transmute(addr_bytes.as_ptr()); + let o = from_raw_parts(o, 8); + Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0))) + }, + _ => Err(DecoderError::RlpInconsistentLengthAndData) + }); + Ok(NodeEndpoint { address: address, udp_port: udp_port }) + } + + pub fn to_rlp(&self, rlp: &mut RlpStream) { + match self.address { + SocketAddr::V4(a) => { + rlp.append(&(&a.ip().octets()[..])); + } + SocketAddr::V6(a) => unsafe { + let o: *const u8 = mem::transmute(a.ip().segments().as_ptr()); + rlp.append(&from_raw_parts(o, 16)); + } + }; + rlp.append(&self.udp_port); + rlp.append(&self.address.port()); + } + + pub fn to_rlp_list(&self, rlp: &mut RlpStream) { + rlp.begin_list(3); + self.to_rlp(rlp); + } + + pub fn is_valid(&self) -> bool { + self.udp_port != 0 && self.address.port() != 0 && + match self.address { + SocketAddr::V4(a) => !a.ip().is_unspecified(), + SocketAddr::V6(a) => !a.ip().is_unspecified() + } + } +} + impl FromStr for NodeEndpoint { type Err = UtilError; @@ -45,7 +99,6 @@ impl FromStr for NodeEndpoint { match address { Ok(Some(a)) => Ok(NodeEndpoint { address: a, - address_str: s.to_owned(), udp_port: a.port() }), Ok(_) => Err(UtilError::AddressResolve(None)), @@ -67,6 +120,17 @@ pub struct Node { pub last_attempted: Option, } +impl Node { + pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { + Node { + id: id, + endpoint: endpoint, + peer_type: PeerType::Optional, + last_attempted: None, + } + } +} + impl FromStr for Node { type Err = UtilError; fn from_str(s: &str) -> Result { @@ -91,7 +155,7 @@ impl PartialEq for Node { self.id == other.id } } -impl Eq for Node { } +impl Eq for Node {} impl Hash for Node { fn hash(&self, state: &mut H) where H: Hasher { diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index 0f1c2c5ad..d93057eb3 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -43,7 +43,10 @@ impl NodeTable { } pub fn update(&mut self, mut update: TableUpdates) { - self.nodes.extend(update.added.drain()); + for (_, node) in update.added.drain() { + let mut entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone())); + entry.endpoint = node.endpoint; + } for r in update.removed { self.nodes.remove(&r); } From 76ea030b7817a3f3c21f4674c987d817de4d7c38 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 01:03:48 +0100 Subject: [PATCH 008/753] Small refactoring --- sync/src/chain.rs | 6 +- util/src/network/discovery.rs | 6 +- util/src/network/handshake.rs | 2 +- util/src/network/host.rs | 106 ++++++++--------- util/src/network/mod.rs | 1 - util/src/network/node.rs | 198 -------------------------------- util/src/network/node_table.rs | 203 ++++++++++++++++++++++++++++++++- util/src/network/session.rs | 2 +- 8 files changed, 257 insertions(+), 267 deletions(-) delete mode 100644 util/src/network/node.rs diff --git a/sync/src/chain.rs b/sync/src/chain.rs index f82162b79..671e2241e 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -82,7 +82,7 @@ const RECEIPTS_PACKET: u8 = 0x10; const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent -const CONNECTION_TIMEOUT_SEC: f64 = 30f64; +const CONNECTION_TIMEOUT_SEC: f64 = 10f64; struct Header { /// Header data @@ -309,7 +309,7 @@ impl ChainSync { } self.peers.insert(peer_id.clone(), peer); - info!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); + debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); self.sync_peer(io, peer_id, false); Ok(()) } @@ -537,7 +537,7 @@ impl ChainSync { pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) { trace!(target: "sync", "== Disconnecting {}", peer); if self.peers.contains_key(&peer) { - info!(target: "sync", "Disconnected {}", peer); + debug!(target: "sync", "Disconnected {}", peer); self.clear_peer_download(peer); self.peers.remove(&peer); self.continue_sync(io); diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index a214f5278..9feef9c74 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -26,7 +26,7 @@ use time; use hash::*; use crypto::*; use rlp::*; -use network::node::*; +use network::node_table::*; use network::error::NetworkError; use io::StreamToken; @@ -227,8 +227,7 @@ impl Discovery { } #[allow(map_clone)] - fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec - { + fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { let mut found: BTreeMap> = BTreeMap::new(); let mut count = 0; @@ -425,6 +424,7 @@ impl Discovery { let node_id: NodeId = try!(r.val_at(3)); let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint }; added.insert(node_id, entry.clone()); + self.ping(&entry.endpoint); self.update_node(entry); } Ok(Some(TableUpdates { added: added, removed: HashSet::new() })) diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 94650b2a7..1fd830ea0 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -24,7 +24,7 @@ use crypto::*; use crypto; use network::connection::{Connection}; use network::host::{HostInfo}; -use network::node::NodeId; +use network::node_table::NodeId; use error::*; use network::error::NetworkError; use network::stats::NetworkStats; diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 47a3d9986..321e965ec 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -32,18 +32,18 @@ use network::session::{Session, SessionData}; use error::*; use io::*; use network::{NetworkProtocolHandler, PROTOCOL_VERSION}; -use network::node::*; +use network::node_table::*; use network::stats::NetworkStats; use network::error::DisconnectReason; use igd::{PortMappingProtocol,search_gateway}; use network::discovery::{Discovery, TableUpdates, NodeEntry}; -use network::node_table::NodeTable; type Slab = ::slab::Slab; const _DEFAULT_PORT: u16 = 30304; const MAX_CONNECTIONS: usize = 1024; const MAINTENANCE_TIMEOUT: u64 = 1000; +const MAX_HANDSHAKES: usize = 100; #[derive(Debug)] /// Network service configuration @@ -226,7 +226,7 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone _ => warn!(target: "net", "Send: Peer is not connected yet") } } else { - warn!(target: "net", "Send: Peer does not exist") + trace!(target: "net", "Send: Peer no longer exist") } Ok(()) } @@ -405,11 +405,23 @@ impl Host where Message: Send + Sync + Clone { } fn have_session(&self, id: &NodeId) -> bool { - self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false }) + self.connections.read().unwrap().iter().any(|e| + match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false }) + } + + fn session_count(&self) -> usize { + self.connections.read().unwrap().iter().filter(|e| + match *e.lock().unwrap().deref() { ConnectionEntry::Session(_) => true, _ => false }).count() } fn connecting_to(&self, id: &NodeId) -> bool { - self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false }) + self.connections.read().unwrap().iter().any(|e| + match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false }) + } + + fn handshake_count(&self) -> usize { + self.connections.read().unwrap().iter().filter(|e| + match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(_) => true, _ => false }).count() } fn keep_alive(&self, io: &IoContext>) { @@ -423,64 +435,40 @@ impl Host where Message: Send + Sync + Clone { } } for p in to_kill { - self.kill_connection(p, io); + self.kill_connection(p, io, true); } } fn connect_peers(&self, io: &IoContext>) { - struct NodeInfo { - id: NodeId, - peer_type: PeerType + let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; + let connections = self.session_count(); + if connections >= ideal_peers as usize { + return; } - let mut to_connect: Vec = Vec::new(); - let mut req_conn = 0; - let pin = self.info.read().unwrap().deref().config.pin; - let ideal_peers = self.info.read().unwrap().deref().config.ideal_peers; - for n in self.nodes.read().unwrap().nodes().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) { - let connected = self.have_session(&n.id) || self.connecting_to(&n.id); - let required = n.peer_type == PeerType::Required; - if connected && required { - req_conn += 1; - } - else if !connected && (!pin || required) { - to_connect.push(n); - } + let handshake_count = self.handshake_count(); + if handshake_count >= MAX_HANDSHAKES { + return; } - for n in &to_connect { - if n.peer_type == PeerType::Required { - if req_conn < ideal_peers { - self.connect_peer(&n.id, io); - } - req_conn += 1; - } - } - if !pin { - let pending_count = 0; //TODO: - let peer_count = 0; - let mut open_slots = ideal_peers - peer_count - pending_count + req_conn; - if open_slots > 0 { - for n in &to_connect { - if n.peer_type == PeerType::Optional && open_slots > 0 { - open_slots -= 1; - self.connect_peer(&n.id, io); - } - } - } + let nodes = { self.nodes.read().unwrap().nodes() }; + + for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)).take(MAX_HANDSHAKES - handshake_count) { + self.connect_peer(&id, io); } + debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); } #[allow(single_match)] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { - debug!("Aborted connect. Node already connected."); + trace!("Aborted connect. Node already connected."); return; } if self.connecting_to(id) { - debug!("Aborted connect. Node already connecting."); + trace!("Aborted connect. Node already connecting."); return; } @@ -542,7 +530,7 @@ impl Host where Message: Send + Sync + Clone { ConnectionEntry::Handshake(ref mut h) => { match h.writable(io, &self.info.read().unwrap()) { Err(e) => { - debug!(target: "net", "Handshake write error: {:?}", e); + debug!(target: "net", "Handshake write error: {}:{:?}", token, e); kill = true; }, Ok(_) => () @@ -554,7 +542,7 @@ impl Host where Message: Send + Sync + Clone { ConnectionEntry::Session(ref mut s) => { match s.writable(io, &self.info.read().unwrap()) { Err(e) => { - debug!(target: "net", "Session write error: {:?}", e); + debug!(target: "net", "Session write error: {}:{:?}", token, e); kill = true; }, Ok(_) => () @@ -564,7 +552,7 @@ impl Host where Message: Send + Sync + Clone { } } if kill { - self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection + self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection return; } else if create_session { self.start_session(token, io); @@ -573,7 +561,7 @@ impl Host where Message: Send + Sync + Clone { } fn connection_closed(&self, token: TimerToken, io: &IoContext>) { - self.kill_connection(token, io); + self.kill_connection(token, io, true); } fn connection_readable(&self, token: StreamToken, io: &IoContext>) { @@ -585,7 +573,7 @@ impl Host where Message: Send + Sync + Clone { match *connection.lock().unwrap().deref_mut() { ConnectionEntry::Handshake(ref mut h) => { if let Err(e) = h.readable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake read error: {:?}", e); + debug!(target: "net", "Handshake read error: {}:{:?}", token, e); kill = true; } if h.done() { @@ -595,7 +583,7 @@ impl Host where Message: Send + Sync + Clone { ConnectionEntry::Session(ref mut s) => { match s.readable(io, &self.info.read().unwrap()) { Err(e) => { - debug!(target: "net", "Handshake read error: {:?}", e); + debug!(target: "net", "Handshake read error: {}:{:?}", token, e); kill = true; }, Ok(SessionData::Ready) => { @@ -621,7 +609,7 @@ impl Host where Message: Send + Sync + Clone { } } if kill { - self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection + self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection return; } else if create_session { self.start_session(token, io); @@ -657,17 +645,20 @@ impl Host where Message: Send + Sync + Clone { } fn connection_timeout(&self, token: StreamToken, io: &IoContext>) { - self.kill_connection(token, io) + self.kill_connection(token, io, true) } - fn kill_connection(&self, token: StreamToken, io: &IoContext>) { + fn kill_connection(&self, token: StreamToken, io: &IoContext>, remote: bool) { let mut to_disconnect: Vec = Vec::new(); { let mut connections = self.connections.write().unwrap(); if let Some(connection) = connections.get(token).cloned() { match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(_) => { + ConnectionEntry::Handshake(ref h) => { connections.remove(token); + if remote { + self.nodes.write().unwrap().note_failure(h.id()); + } }, ConnectionEntry::Session(ref mut s) if s.is_ready() => { for (p, _) in self.handlers.read().unwrap().iter() { @@ -676,6 +667,9 @@ impl Host where Message: Send + Sync + Clone { } } connections.remove(token); + if remote { + self.nodes.write().unwrap().note_failure(s.id()); + } }, _ => {}, } @@ -706,7 +700,7 @@ impl Host where Message: Send + Sync + Clone { } } for i in to_remove { - self.kill_connection(i, io); + self.kill_connection(i, io, false); } self.nodes.write().unwrap().update(node_changes); } @@ -816,7 +810,7 @@ impl IoHandler> for Host where Messa ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } } } - self.kill_connection(*peer, io); + self.kill_connection(*peer, io, false); }, NetworkIoMessage::User(ref message) => { for (p, h) in self.handlers.read().unwrap().iter() { diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index 466ef4e6a..7d5aac8f7 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -71,7 +71,6 @@ mod session; mod discovery; mod service; mod error; -mod node; mod node_table; mod stats; diff --git a/util/src/network/node.rs b/util/src/network/node.rs deleted file mode 100644 index d8370bc79..000000000 --- a/util/src/network/node.rs +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::mem; -use std::slice::from_raw_parts; -use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; -use std::hash::{Hash, Hasher}; -use std::str::{FromStr}; -use hash::*; -use rlp::*; -use time::Tm; -use error::*; - -/// Node public key -pub type NodeId = H512; - -#[derive(Debug, Clone)] -/// Node address info -pub struct NodeEndpoint { - /// IP(V4 or V6) address - pub address: SocketAddr, - /// Conneciton port. - pub udp_port: u16 -} - -impl NodeEndpoint { - pub fn udp_address(&self) -> SocketAddr { - match self.address { - SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)), - SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())), - } - } -} - -impl NodeEndpoint { - pub fn from_rlp(rlp: &UntrustedRlp) -> Result { - let tcp_port = try!(rlp.val_at::(2)); - let udp_port = try!(rlp.val_at::(1)); - let addr_bytes = try!(try!(rlp.at(0)).data()); - let address = try!(match addr_bytes.len() { - 4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))), - 16 => unsafe { - let o: *const u16 = mem::transmute(addr_bytes.as_ptr()); - let o = from_raw_parts(o, 8); - Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0))) - }, - _ => Err(DecoderError::RlpInconsistentLengthAndData) - }); - Ok(NodeEndpoint { address: address, udp_port: udp_port }) - } - - pub fn to_rlp(&self, rlp: &mut RlpStream) { - match self.address { - SocketAddr::V4(a) => { - rlp.append(&(&a.ip().octets()[..])); - } - SocketAddr::V6(a) => unsafe { - let o: *const u8 = mem::transmute(a.ip().segments().as_ptr()); - rlp.append(&from_raw_parts(o, 16)); - } - }; - rlp.append(&self.udp_port); - rlp.append(&self.address.port()); - } - - pub fn to_rlp_list(&self, rlp: &mut RlpStream) { - rlp.begin_list(3); - self.to_rlp(rlp); - } - - pub fn is_valid(&self) -> bool { - self.udp_port != 0 && self.address.port() != 0 && - match self.address { - SocketAddr::V4(a) => !a.ip().is_unspecified(), - SocketAddr::V6(a) => !a.ip().is_unspecified() - } - } -} - -impl FromStr for NodeEndpoint { - type Err = UtilError; - - /// Create endpoint from string. Performs name resolution if given a host name. - fn from_str(s: &str) -> Result { - let address = s.to_socket_addrs().map(|mut i| i.next()); - match address { - Ok(Some(a)) => Ok(NodeEndpoint { - address: a, - udp_port: a.port() - }), - Ok(_) => Err(UtilError::AddressResolve(None)), - Err(e) => Err(UtilError::AddressResolve(Some(e))) - } - } -} - -#[derive(PartialEq, Eq, Copy, Clone)] -pub enum PeerType { - Required, - Optional -} - -pub struct Node { - pub id: NodeId, - pub endpoint: NodeEndpoint, - pub peer_type: PeerType, - pub last_attempted: Option, -} - -impl Node { - pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { - Node { - id: id, - endpoint: endpoint, - peer_type: PeerType::Optional, - last_attempted: None, - } - } -} - -impl FromStr for Node { - type Err = UtilError; - fn from_str(s: &str) -> Result { - let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" { - (try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..]))) - } - else { - (NodeId::new(), try!(NodeEndpoint::from_str(s))) - }; - - Ok(Node { - id: id, - endpoint: endpoint, - peer_type: PeerType::Optional, - last_attempted: None, - }) - } -} - -impl PartialEq for Node { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} -impl Eq for Node {} - -impl Hash for Node { - fn hash(&self, state: &mut H) where H: Hasher { - self.id.hash(state) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::str::FromStr; - use std::net::*; - use hash::*; - - #[test] - fn endpoint_parse() { - let endpoint = NodeEndpoint::from_str("123.99.55.44:7770"); - assert!(endpoint.is_ok()); - let v4 = match endpoint.unwrap().address { - SocketAddr::V4(v4address) => v4address, - _ => panic!("should ve v4 address") - }; - assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4); - } - - #[test] - fn node_parse() { - let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); - assert!(node.is_ok()); - let node = node.unwrap(); - let v4 = match node.endpoint.address { - SocketAddr::V4(v4address) => v4address, - _ => panic!("should ve v4 address") - }; - assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4); - assert_eq!( - H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(), - node.id); - } -} diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index d93057eb3..a3ee57481 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -14,11 +14,161 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::mem; +use std::slice::from_raw_parts; +use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; +use std::hash::{Hash, Hasher}; +use std::str::{FromStr}; use std::collections::HashMap; -use std::collections::hash_map::Values; -use network::node::*; +use hash::*; +use rlp::*; +use time::Tm; +use error::*; use network::discovery::TableUpdates; +/// Node public key +pub type NodeId = H512; + +#[derive(Debug, Clone)] +/// Node address info +pub struct NodeEndpoint { + /// IP(V4 or V6) address + pub address: SocketAddr, + /// Conneciton port. + pub udp_port: u16 +} + +impl NodeEndpoint { + pub fn udp_address(&self) -> SocketAddr { + match self.address { + SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)), + SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())), + } + } +} + +impl NodeEndpoint { + pub fn from_rlp(rlp: &UntrustedRlp) -> Result { + let tcp_port = try!(rlp.val_at::(2)); + let udp_port = try!(rlp.val_at::(1)); + let addr_bytes = try!(try!(rlp.at(0)).data()); + let address = try!(match addr_bytes.len() { + 4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))), + 16 => unsafe { + let o: *const u16 = mem::transmute(addr_bytes.as_ptr()); + let o = from_raw_parts(o, 8); + Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0))) + }, + _ => Err(DecoderError::RlpInconsistentLengthAndData) + }); + Ok(NodeEndpoint { address: address, udp_port: udp_port }) + } + + pub fn to_rlp(&self, rlp: &mut RlpStream) { + match self.address { + SocketAddr::V4(a) => { + rlp.append(&(&a.ip().octets()[..])); + } + SocketAddr::V6(a) => unsafe { + let o: *const u8 = mem::transmute(a.ip().segments().as_ptr()); + rlp.append(&from_raw_parts(o, 16)); + } + }; + rlp.append(&self.udp_port); + rlp.append(&self.address.port()); + } + + pub fn to_rlp_list(&self, rlp: &mut RlpStream) { + rlp.begin_list(3); + self.to_rlp(rlp); + } + + pub fn is_valid(&self) -> bool { + self.udp_port != 0 && self.address.port() != 0 && + match self.address { + SocketAddr::V4(a) => !a.ip().is_unspecified(), + SocketAddr::V6(a) => !a.ip().is_unspecified() + } + } +} + +impl FromStr for NodeEndpoint { + type Err = UtilError; + + /// Create endpoint from string. Performs name resolution if given a host name. + fn from_str(s: &str) -> Result { + let address = s.to_socket_addrs().map(|mut i| i.next()); + match address { + Ok(Some(a)) => Ok(NodeEndpoint { + address: a, + udp_port: a.port() + }), + Ok(_) => Err(UtilError::AddressResolve(None)), + Err(e) => Err(UtilError::AddressResolve(Some(e))) + } + } +} + +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum PeerType { + _Required, + Optional +} + +pub struct Node { + pub id: NodeId, + pub endpoint: NodeEndpoint, + pub peer_type: PeerType, + pub failures: u32, + pub last_attempted: Option, +} + +impl Node { + pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { + Node { + id: id, + endpoint: endpoint, + peer_type: PeerType::Optional, + failures: 0, + last_attempted: None, + } + } +} + +impl FromStr for Node { + type Err = UtilError; + fn from_str(s: &str) -> Result { + let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" { + (try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..]))) + } + else { + (NodeId::new(), try!(NodeEndpoint::from_str(s))) + }; + + Ok(Node { + id: id, + endpoint: endpoint, + peer_type: PeerType::Optional, + last_attempted: None, + failures: 0, + }) + } +} + +impl PartialEq for Node { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} +impl Eq for Node {} + +impl Hash for Node { + fn hash(&self, state: &mut H) where H: Hasher { + self.id.hash(state) + } +} + +/// Node table backed by disk file. pub struct NodeTable { nodes: HashMap } @@ -30,18 +180,24 @@ impl NodeTable { } } + /// Add a node to table pub fn add_node(&mut self, node: Node) { self.nodes.insert(node.id.clone(), node); } - pub fn nodes(&self) -> Values { - self.nodes.values() + /// Returns node ids sorted by number of failures + pub fn nodes(&self) -> Vec { + let mut refs: Vec<&Node> = self.nodes.values().collect(); + refs.sort_by(|a, b| a.failures.cmp(&b.failures)); + refs.iter().map(|n| n.id.clone()).collect() } + /// Get particular node pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> { self.nodes.get_mut(id) } + /// Apply table changes coming from discovery pub fn update(&mut self, mut update: TableUpdates) { for (_, node) in update.added.drain() { let mut entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone())); @@ -52,4 +208,43 @@ impl NodeTable { } } + pub fn note_failure(&mut self, id: &NodeId) { + if let Some(node) = self.nodes.get_mut(id) { + node.failures += 1; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + use std::net::*; + use hash::*; + + #[test] + fn endpoint_parse() { + let endpoint = NodeEndpoint::from_str("123.99.55.44:7770"); + assert!(endpoint.is_ok()); + let v4 = match endpoint.unwrap().address { + SocketAddr::V4(v4address) => v4address, + _ => panic!("should ve v4 address") + }; + assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4); + } + + #[test] + fn node_parse() { + let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); + assert!(node.is_ok()); + let node = node.unwrap(); + let v4 = match node.endpoint.address { + SocketAddr::V4(v4address) => v4address, + _ => panic!("should ve v4 address") + }; + assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4); + assert_eq!( + H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(), + node.id); + } } diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 19e2cf08e..3b49a8f5e 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -23,7 +23,7 @@ use error::*; use io::{IoContext, StreamToken}; use network::error::{NetworkError, DisconnectReason}; use network::host::*; -use network::node::NodeId; +use network::node_table::NodeId; use time; const PING_TIMEOUT_SEC: u64 = 30; From 9768fddb19e76a82bbee4c071d6fd4b88e181fe7 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 01:05:54 +0100 Subject: [PATCH 009/753] Homestead block set to 1100000 --- ethcore/res/ethereum/frontier.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index 301441958..6e31a2fce 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -3,7 +3,7 @@ "engineName": "Ethash", "params": { "accountStartNonce": "0x00", - "frontierCompatibilityModeLimit": "0xf4240", + "frontierCompatibilityModeLimit": "0x10c8e0", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", From 2d89708ea8cc034bc625df68c02ff6511fbfce90 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 02:11:55 +0100 Subject: [PATCH 010/753] Reduced thread contention --- util/src/network/host.rs | 91 ++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 321e965ec..5c08ad5c8 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -215,7 +215,8 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone /// Send a packet over the network to another peer. pub fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), UtilError> { - if let Some(connection) = self.connections.read().unwrap().get(peer).cloned() { + let connection = { self.connections.read().unwrap().get(peer).cloned() }; + if let Some(connection) = connection { match *connection.lock().unwrap().deref_mut() { ConnectionEntry::Session(ref mut s) => { s.send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| { @@ -264,7 +265,8 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone /// Returns peer identification string pub fn peer_info(&self, peer: PeerId) -> String { - if let Some(connection) = self.connections.read().unwrap().get(peer).cloned() { + let connection = { self.connections.read().unwrap().get(peer).cloned() }; + if let Some(connection) = connection { if let ConnectionEntry::Session(ref s) = *connection.lock().unwrap().deref() { return s.info.client_version.clone() } @@ -525,7 +527,8 @@ impl Host where Message: Send + Sync + Clone { fn connection_writable(&self, token: StreamToken, io: &IoContext>) { let mut create_session = false; let mut kill = false; - if let Some(connection) = self.connections.read().unwrap().get(token).cloned() { + let connection = { self.connections.read().unwrap().get(token).cloned() }; + if let Some(connection) = connection { match *connection.lock().unwrap().deref_mut() { ConnectionEntry::Handshake(ref mut h) => { match h.writable(io, &self.info.read().unwrap()) { @@ -569,7 +572,8 @@ impl Host where Message: Send + Sync + Clone { let mut packet_data: Option<(ProtocolId, PacketId, Vec)> = None; let mut create_session = false; let mut kill = false; - if let Some(connection) = self.connections.read().unwrap().get(token).cloned() { + let connection = { self.connections.read().unwrap().get(token).cloned() }; + if let Some(connection) = connection { match *connection.lock().unwrap().deref_mut() { ConnectionEntry::Handshake(ref mut h) => { if let Err(e) = h.readable(io, &self.info.read().unwrap()) { @@ -628,20 +632,28 @@ impl Host where Message: Send + Sync + Clone { fn start_session(&self, token: StreamToken, io: &IoContext>) { let mut connections = self.connections.write().unwrap(); - if connections.get(token).is_none() { - return; // handshake expired + let replace = { + let connection = { connections.get(token).cloned() }; + if let Some(connection) = connection { + match *connection.lock().unwrap().deref_mut() { + ConnectionEntry::Handshake(_) => true, + _ => false, + } + } else { false } + }; + if replace { + connections.replace_with(token, |c| { + match Arc::try_unwrap(c).ok().unwrap().into_inner().unwrap() { + ConnectionEntry::Handshake(h) => { + let session = Session::new(h, io, &self.info.read().unwrap()).expect("Session creation error"); + io.update_registration(token).expect("Error updating session registration"); + self.stats.inc_sessions(); + Some(Arc::new(Mutex::new(ConnectionEntry::Session(session)))) + }, + _ => { None } // handshake expired + } + }).ok(); } - connections.replace_with(token, |c| { - match Arc::try_unwrap(c).ok().unwrap().into_inner().unwrap() { - ConnectionEntry::Handshake(h) => { - let session = Session::new(h, io, &self.info.read().unwrap()).expect("Session creation error"); - io.update_registration(token).expect("Error updating session registration"); - self.stats.inc_sessions(); - Some(Arc::new(Mutex::new(ConnectionEntry::Session(session)))) - }, - _ => { None } // handshake expired - } - }).ok(); } fn connection_timeout(&self, token: StreamToken, io: &IoContext>) { @@ -650,15 +662,14 @@ impl Host where Message: Send + Sync + Clone { fn kill_connection(&self, token: StreamToken, io: &IoContext>, remote: bool) { let mut to_disconnect: Vec = Vec::new(); + let mut failure_id = None; { let mut connections = self.connections.write().unwrap(); if let Some(connection) = connections.get(token).cloned() { match *connection.lock().unwrap().deref_mut() { ConnectionEntry::Handshake(ref h) => { connections.remove(token); - if remote { - self.nodes.write().unwrap().note_failure(h.id()); - } + failure_id = Some(h.id().clone()); }, ConnectionEntry::Session(ref mut s) if s.is_ready() => { for (p, _) in self.handlers.read().unwrap().iter() { @@ -667,15 +678,18 @@ impl Host where Message: Send + Sync + Clone { } } connections.remove(token); - if remote { - self.nodes.write().unwrap().note_failure(s.id()); - } + failure_id = Some(s.id().clone()); }, _ => {}, } } io.deregister_stream(token).expect("Error deregistering stream"); } + if let Some(id) = failure_id { + if remote { + self.nodes.write().unwrap().note_failure(&id); + } + } for p in to_disconnect { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); h.disconnected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token); @@ -683,18 +697,20 @@ impl Host where Message: Send + Sync + Clone { } fn update_nodes(&self, io: &IoContext>, node_changes: TableUpdates) { - let connections = self.connections.write().unwrap(); let mut to_remove: Vec = Vec::new(); - for c in connections.iter() { - match *c.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(ref h) => { - if node_changes.removed.contains(&h.id()) { - to_remove.push(h.token()); + { + let connections = self.connections.write().unwrap(); + for c in connections.iter() { + match *c.lock().unwrap().deref_mut() { + ConnectionEntry::Handshake(ref h) => { + if node_changes.removed.contains(&h.id()) { + to_remove.push(h.token()); + } } - } - ConnectionEntry::Session(ref s) => { - if node_changes.removed.contains(&s.id()) { - to_remove.push(s.token()); + ConnectionEntry::Session(ref s) => { + if node_changes.removed.contains(&s.id()) { + to_remove.push(s.token()); + } } } } @@ -804,7 +820,8 @@ impl IoHandler> for Host where Messa io.register_timer(handler_token, *delay).expect("Error registering timer"); }, NetworkIoMessage::Disconnect(ref peer) => { - if let Some(connection) = self.connections.read().unwrap().get(*peer).cloned() { + let connection = { self.connections.read().unwrap().get(*peer).cloned() }; + if let Some(connection) = connection { match *connection.lock().unwrap().deref_mut() { ConnectionEntry::Handshake(_) => {}, ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } @@ -823,7 +840,8 @@ impl IoHandler> for Host where Messa fn register_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { FIRST_CONNECTION ... LAST_CONNECTION => { - if let Some(connection) = self.connections.read().unwrap().get(stream).cloned() { + let connection = { self.connections.read().unwrap().get(stream).cloned() }; + if let Some(connection) = connection { match *connection.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.register_socket(reg, event_loop).expect("Error registering socket"), ConnectionEntry::Session(_) => warn!("Unexpected session stream registration") @@ -857,7 +875,8 @@ impl IoHandler> for Host where Messa fn update_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { FIRST_CONNECTION ... LAST_CONNECTION => { - if let Some(connection) = self.connections.read().unwrap().get(stream).cloned() { + let connection = { self.connections.read().unwrap().get(stream).cloned() }; + if let Some(connection) = connection { match *connection.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.update_socket(reg, event_loop).expect("Error updating socket"), ConnectionEntry::Session(ref s) => s.update_socket(reg, event_loop).expect("Error updating socket"), From 718646f943b1388fb68afa95f5e79aca13e53a93 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 11:34:59 +0100 Subject: [PATCH 011/753] Refactored host to use different containers for handshakes and sessions --- util/src/network/connection.rs | 10 + util/src/network/host.rs | 435 +++++++++++++++++---------------- util/src/network/session.rs | 3 +- 3 files changed, 233 insertions(+), 215 deletions(-) diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 44d429164..242e8935e 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -164,6 +164,11 @@ impl Connection { self.token } + /// Replace socket token + pub fn set_token(&mut self, token: StreamToken) { + self.token = token; + } + /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "net", "connection register; token={:?}", reg); @@ -243,6 +248,11 @@ impl EncryptedConnection { self.connection.token } + /// Replace socket token + pub fn set_token(&mut self, token: StreamToken) { + self.connection.set_token(token); + } + /// Create an encrypted connection out of the handshake. Consumes a handshake object. pub fn new(mut handshake: Handshake) -> Result { let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public)); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 5c08ad5c8..04dda02bd 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -20,6 +20,7 @@ use std::hash::{Hasher}; use std::str::{FromStr}; use std::sync::*; use std::ops::*; +use std::cmp::min; use mio::*; use mio::tcp::*; use target_info::Target; @@ -41,9 +42,10 @@ use network::discovery::{Discovery, TableUpdates, NodeEntry}; type Slab = ::slab::Slab; const _DEFAULT_PORT: u16 = 30304; -const MAX_CONNECTIONS: usize = 1024; +const MAX_SESSIONS: usize = 1024; +const MAX_HANDSHAKES: usize = 256; +const MAX_HANDSHAKES_PER_ROUND: usize = 64; const MAINTENANCE_TIMEOUT: u64 = 1000; -const MAX_HANDSHAKES: usize = 100; #[derive(Debug)] /// Network service configuration @@ -132,13 +134,16 @@ impl NetworkConfiguration { } // Tokens -const TCP_ACCEPT: usize = MAX_CONNECTIONS + 1; -const IDLE: usize = MAX_CONNECTIONS + 2; -const DISCOVERY: usize = MAX_CONNECTIONS + 3; -const DISCOVERY_REFRESH: usize = MAX_CONNECTIONS + 4; -const DISCOVERY_ROUND: usize = MAX_CONNECTIONS + 5; -const FIRST_CONNECTION: usize = 0; -const LAST_CONNECTION: usize = FIRST_CONNECTION + MAX_CONNECTIONS - 1; +const TCP_ACCEPT: usize = LAST_HANDSHAKE + 1; +const IDLE: usize = LAST_HANDSHAKE + 2; +const DISCOVERY: usize = LAST_HANDSHAKE + 3; +const DISCOVERY_REFRESH: usize = LAST_HANDSHAKE + 4; +const DISCOVERY_ROUND: usize = LAST_HANDSHAKE + 5; +const FIRST_SESSION: usize = 0; +const LAST_SESSION: usize = FIRST_SESSION + MAX_SESSIONS - 1; +const FIRST_HANDSHAKE: usize = LAST_SESSION + 1; +const LAST_HANDSHAKE: usize = FIRST_HANDSHAKE + MAX_HANDSHAKES - 1; +const USER_TIMER: usize = LAST_HANDSHAKE + 256; /// Protocol handler level packet id pub type PacketId = u8; @@ -196,7 +201,7 @@ impl Encodable for CapabilityInfo { pub struct NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'static, 's { io: &'s IoContext>, protocol: ProtocolId, - connections: Arc>>, + sessions: Arc>>, session: Option, } @@ -204,28 +209,23 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone /// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler. fn new(io: &'s IoContext>, protocol: ProtocolId, - session: Option, connections: Arc>>) -> NetworkContext<'s, Message> { + session: Option, sessions: Arc>>) -> NetworkContext<'s, Message> { NetworkContext { io: io, protocol: protocol, session: session, - connections: connections, + sessions: sessions, } } /// Send a packet over the network to another peer. pub fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), UtilError> { - let connection = { self.connections.read().unwrap().get(peer).cloned() }; - if let Some(connection) = connection { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Session(ref mut s) => { - s.send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| { + let session = { self.sessions.read().unwrap().get(peer).cloned() }; + if let Some(session) = session { + session.lock().unwrap().deref_mut().send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| { warn!(target: "net", "Send error: {:?}", e); }); //TODO: don't copy vector data - try!(self.io.update_registration(peer)); - }, - _ => warn!(target: "net", "Send: Peer is not connected yet") - } + try!(self.io.update_registration(peer)); } else { trace!(target: "net", "Send: Peer no longer exist") } @@ -265,11 +265,9 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone /// Returns peer identification string pub fn peer_info(&self, peer: PeerId) -> String { - let connection = { self.connections.read().unwrap().get(peer).cloned() }; - if let Some(connection) = connection { - if let ConnectionEntry::Session(ref s) = *connection.lock().unwrap().deref() { - return s.info.client_version.clone() - } + let session = { self.sessions.read().unwrap().get(peer).cloned() }; + if let Some(session) = session { + return session.lock().unwrap().info.client_version.clone() } "unknown".to_owned() } @@ -311,12 +309,8 @@ impl HostInfo { } } -enum ConnectionEntry { - Handshake(Handshake), - Session(Session) -} - -type SharedConnectionEntry = Arc>; +type SharedSession = Arc>; +type SharedHandshake = Arc>; #[derive(Copy, Clone)] struct ProtocolTimer { @@ -328,7 +322,8 @@ struct ProtocolTimer { pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, tcp_listener: Mutex, - connections: Arc>>, + handshakes: Arc>>, + sessions: Arc>>, discovery: Mutex, nodes: RwLock, handlers: RwLock>>>, @@ -361,11 +356,12 @@ impl Host where Message: Send + Sync + Clone { }), discovery: Mutex::new(discovery), tcp_listener: Mutex::new(tcp_listener), - connections: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS))), + handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), + sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), handlers: RwLock::new(HashMap::new()), timers: RwLock::new(HashMap::new()), - timer_counter: RwLock::new(LAST_CONNECTION + 1), + timer_counter: RwLock::new(USER_TIMER), stats: Arc::new(NetworkStats::default()), }; let port = host.info.read().unwrap().config.listen_address.port(); @@ -407,33 +403,28 @@ impl Host where Message: Send + Sync + Clone { } fn have_session(&self, id: &NodeId) -> bool { - self.connections.read().unwrap().iter().any(|e| - match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false }) + self.sessions.read().unwrap().iter().any(|e| e.lock().unwrap().info.id.eq(&id)) } fn session_count(&self) -> usize { - self.connections.read().unwrap().iter().filter(|e| - match *e.lock().unwrap().deref() { ConnectionEntry::Session(_) => true, _ => false }).count() + self.sessions.read().unwrap().count() } fn connecting_to(&self, id: &NodeId) -> bool { - self.connections.read().unwrap().iter().any(|e| - match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false }) + self.handshakes.read().unwrap().iter().any(|e| e.lock().unwrap().id.eq(&id)) } fn handshake_count(&self) -> usize { - self.connections.read().unwrap().iter().filter(|e| - match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(_) => true, _ => false }).count() + self.handshakes.read().unwrap().count() } fn keep_alive(&self, io: &IoContext>) { let mut to_kill = Vec::new(); - for e in self.connections.write().unwrap().iter_mut() { - if let ConnectionEntry::Session(ref mut s) = *e.lock().unwrap().deref_mut() { - if !s.keep_alive(io) { - s.disconnect(DisconnectReason::PingTimeout); - to_kill.push(s.token()); - } + for e in self.sessions.write().unwrap().iter_mut() { + let mut s = e.lock().unwrap(); + if !s.keep_alive(io) { + s.disconnect(DisconnectReason::PingTimeout); + to_kill.push(s.token()); } } for p in to_kill { @@ -443,8 +434,8 @@ impl Host where Message: Send + Sync + Clone { fn connect_peers(&self, io: &IoContext>) { let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; - let connections = self.session_count(); - if connections >= ideal_peers as usize { + let session_count = self.session_count(); + if session_count >= ideal_peers as usize { return; } @@ -453,10 +444,9 @@ impl Host where Message: Send + Sync + Clone { return; } - let nodes = { self.nodes.read().unwrap().nodes() }; - - for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)).take(MAX_HANDSHAKES - handshake_count) { + for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)) + .take(min(MAX_HANDSHAKES_PER_ROUND, MAX_HANDSHAKES - handshake_count)) { self.connect_peer(&id, io); } debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); @@ -495,15 +485,15 @@ impl Host where Message: Send + Sync + Clone { #[allow(block_in_if_condition_stmt)] fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) { let nonce = self.info.write().unwrap().next_nonce(); - let mut connections = self.connections.write().unwrap(); - if connections.insert_with(|token| { + let mut handshakes = self.handshakes.write().unwrap(); + if handshakes.insert_with(|token| { let mut handshake = Handshake::new(token, id, socket, &nonce, self.stats.clone()).expect("Can't create handshake"); handshake.start(io, &self.info.read().unwrap(), id.is_some()).and_then(|_| io.register_stream(token)).unwrap_or_else (|e| { debug!(target: "net", "Handshake create error: {:?}", e); }); - Arc::new(Mutex::new(ConnectionEntry::Handshake(handshake))) + Arc::new(Mutex::new(handshake)) }).is_none() { - warn!("Max connections reached"); + warn!("Max handshakes reached"); } } @@ -523,35 +513,18 @@ impl Host where Message: Send + Sync + Clone { io.update_registration(TCP_ACCEPT).expect("Error registering TCP listener"); } - #[allow(single_match)] - fn connection_writable(&self, token: StreamToken, io: &IoContext>) { + fn handshake_writable(&self, token: StreamToken, io: &IoContext>) { let mut create_session = false; let mut kill = false; - let connection = { self.connections.read().unwrap().get(token).cloned() }; - if let Some(connection) = connection { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(ref mut h) => { - match h.writable(io, &self.info.read().unwrap()) { - Err(e) => { - debug!(target: "net", "Handshake write error: {}:{:?}", token, e); - kill = true; - }, - Ok(_) => () - } - if h.done() { - create_session = true; - } - }, - ConnectionEntry::Session(ref mut s) => { - match s.writable(io, &self.info.read().unwrap()) { - Err(e) => { - debug!(target: "net", "Session write error: {}:{:?}", token, e); - kill = true; - }, - Ok(_) => () - } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); - } + let handshake = { self.handshakes.read().unwrap().get(token).cloned() }; + if let Some(handshake) = handshake { + let mut h = handshake.lock().unwrap(); + if let Err(e) = h.writable(io, &self.info.read().unwrap()) { + debug!(target: "net", "Handshake write error: {}:{:?}", token, e); + kill = true; + } + if h.done() { + create_session = true; } } if kill { @@ -563,55 +536,40 @@ impl Host where Message: Send + Sync + Clone { } } + fn session_writable(&self, token: StreamToken, io: &IoContext>) { + let mut kill = false; + let session = { self.sessions.read().unwrap().get(token).cloned() }; + if let Some(session) = session { + let mut s = session.lock().unwrap(); + if let Err(e) = s.writable(io, &self.info.read().unwrap()) { + debug!(target: "net", "Session write error: {}:{:?}", token, e); + kill = true; + } + io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); + } + if kill { + self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection + } + } + fn connection_closed(&self, token: TimerToken, io: &IoContext>) { self.kill_connection(token, io, true); } - fn connection_readable(&self, token: StreamToken, io: &IoContext>) { - let mut ready_data: Vec = Vec::new(); - let mut packet_data: Option<(ProtocolId, PacketId, Vec)> = None; + fn handshake_readable(&self, token: StreamToken, io: &IoContext>) { let mut create_session = false; let mut kill = false; - let connection = { self.connections.read().unwrap().get(token).cloned() }; - if let Some(connection) = connection { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(ref mut h) => { - if let Err(e) = h.readable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake read error: {}:{:?}", token, e); - kill = true; - } - if h.done() { - create_session = true; - } - }, - ConnectionEntry::Session(ref mut s) => { - match s.readable(io, &self.info.read().unwrap()) { - Err(e) => { - debug!(target: "net", "Handshake read error: {}:{:?}", token, e); - kill = true; - }, - Ok(SessionData::Ready) => { - for (p, _) in self.handlers.read().unwrap().iter() { - if s.have_capability(p) { - ready_data.push(p); - } - } - }, - Ok(SessionData::Packet { - data, - protocol, - packet_id, - }) => { - match self.handlers.read().unwrap().get(protocol) { - None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) }, - Some(_) => packet_data = Some((protocol, packet_id, data)), - } - }, - Ok(SessionData::None) => {}, - } - } + let handshake = { self.handshakes.read().unwrap().get(token).cloned() }; + if let Some(handshake) = handshake { + let mut h = handshake.lock().unwrap(); + if let Err(e) = h.readable(io, &self.info.read().unwrap()) { + debug!(target: "net", "Handshake read error: {}:{:?}", token, e); + kill = true; } - } + if h.done() { + create_session = true; + } + } if kill { self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection return; @@ -619,40 +577,74 @@ impl Host where Message: Send + Sync + Clone { self.start_session(token, io); io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); } + io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); + } + + fn session_readable(&self, token: StreamToken, io: &IoContext>) { + let mut ready_data: Vec = Vec::new(); + let mut packet_data: Option<(ProtocolId, PacketId, Vec)> = None; + let mut kill = false; + let session = { self.sessions.read().unwrap().get(token).cloned() }; + if let Some(session) = session { + let mut s = session.lock().unwrap(); + match s.readable(io, &self.info.read().unwrap()) { + Err(e) => { + debug!(target: "net", "Session read error: {}:{:?}", token, e); + kill = true; + }, + Ok(SessionData::Ready) => { + for (p, _) in self.handlers.read().unwrap().iter() { + if s.have_capability(p) { + ready_data.push(p); + } + } + }, + Ok(SessionData::Packet { + data, + protocol, + packet_id, + }) => { + match self.handlers.read().unwrap().get(protocol) { + None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) }, + Some(_) => packet_data = Some((protocol, packet_id, data)), + } + }, + Ok(SessionData::None) => {}, + } + } + if kill { + self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection + return; + } for p in ready_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.connected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token); + h.connected(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token); } if let Some((p, packet_id, data)) = packet_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.read(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token, packet_id, &data[1..]); + h.read(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token, packet_id, &data[1..]); } io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); } fn start_session(&self, token: StreamToken, io: &IoContext>) { - let mut connections = self.connections.write().unwrap(); - let replace = { - let connection = { connections.get(token).cloned() }; - if let Some(connection) = connection { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(_) => true, - _ => false, - } - } else { false } - }; - if replace { - connections.replace_with(token, |c| { - match Arc::try_unwrap(c).ok().unwrap().into_inner().unwrap() { - ConnectionEntry::Handshake(h) => { - let session = Session::new(h, io, &self.info.read().unwrap()).expect("Session creation error"); - io.update_registration(token).expect("Error updating session registration"); - self.stats.inc_sessions(); - Some(Arc::new(Mutex::new(ConnectionEntry::Session(session)))) - }, - _ => { None } // handshake expired - } - }).ok(); + let mut handshakes = self.handshakes.write().unwrap(); + if handshakes.get(token).is_none() { + return; + } + + // turn a handshake into a session + let mut sessions = self.sessions.write().unwrap(); + let h = handshakes.remove(token).unwrap(); + let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap(); + let result = sessions.insert_with(move |session_token| { + let session = Session::new(h, session_token, &self.info.read().unwrap()).expect("Session creation error"); + io.update_registration(session_token).expect("Error updating session registration"); + self.stats.inc_sessions(); + Arc::new(Mutex::new(session)) + }); + if result.is_none() { + warn!("Max sessions reached"); } } @@ -663,28 +655,32 @@ impl Host where Message: Send + Sync + Clone { fn kill_connection(&self, token: StreamToken, io: &IoContext>, remote: bool) { let mut to_disconnect: Vec = Vec::new(); let mut failure_id = None; - { - let mut connections = self.connections.write().unwrap(); - if let Some(connection) = connections.get(token).cloned() { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(ref h) => { - connections.remove(token); - failure_id = Some(h.id().clone()); - }, - ConnectionEntry::Session(ref mut s) if s.is_ready() => { + match token { + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let mut handshakes = self.handshakes.write().unwrap(); + if let Some(handshake) = handshakes.get(token).cloned() { + failure_id = Some(handshake.lock().unwrap().id().clone()); + handshakes.remove(token); + } + }, + FIRST_SESSION ... LAST_SESSION => { + let mut sessions = self.sessions.write().unwrap(); + if let Some(session) = sessions.get(token).cloned() { + let s = session.lock().unwrap(); + if s.is_ready() { for (p, _) in self.handlers.read().unwrap().iter() { if s.have_capability(p) { to_disconnect.push(p); } } - connections.remove(token); - failure_id = Some(s.id().clone()); - }, - _ => {}, + } + failure_id = Some(s.id().clone()); + sessions.remove(token); } - } - io.deregister_stream(token).expect("Error deregistering stream"); + }, + _ => {}, } + io.deregister_stream(token).expect("Error deregistering stream"); if let Some(id) = failure_id { if remote { self.nodes.write().unwrap().note_failure(&id); @@ -692,25 +688,28 @@ impl Host where Message: Send + Sync + Clone { } for p in to_disconnect { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.disconnected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token); + h.disconnected(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token); } } fn update_nodes(&self, io: &IoContext>, node_changes: TableUpdates) { let mut to_remove: Vec = Vec::new(); { - let connections = self.connections.write().unwrap(); - for c in connections.iter() { - match *c.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(ref h) => { - if node_changes.removed.contains(&h.id()) { - to_remove.push(h.token()); - } + { + let handshakes = self.handshakes.write().unwrap(); + for c in handshakes.iter() { + let h = c.lock().unwrap(); + if node_changes.removed.contains(&h.id()) { + to_remove.push(h.token()); } - ConnectionEntry::Session(ref s) => { - if node_changes.removed.contains(&s.id()) { - to_remove.push(s.token()); - } + } + } + { + let sessions = self.sessions.write().unwrap(); + for c in sessions.iter() { + let s = c.lock().unwrap(); + if node_changes.removed.contains(&s.id()) { + to_remove.push(s.token()); } } } @@ -735,14 +734,16 @@ impl IoHandler> for Host where Messa fn stream_hup(&self, io: &IoContext>, stream: StreamToken) { trace!(target: "net", "Hup: {}", stream); match stream { - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_closed(stream, io), + FIRST_SESSION ... LAST_SESSION => self.connection_closed(stream, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_closed(stream, io), _ => warn!(target: "net", "Unexpected hup"), }; } fn stream_readable(&self, io: &IoContext>, stream: StreamToken) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_readable(stream, io), + FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), DISCOVERY => { if let Some(node_changes) = self.discovery.lock().unwrap().readable() { self.update_nodes(io, node_changes); @@ -756,7 +757,8 @@ impl IoHandler> for Host where Messa fn stream_writable(&self, io: &IoContext>, stream: StreamToken) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io), + FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io), DISCOVERY => { self.discovery.lock().unwrap().writable(); io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); @@ -768,7 +770,8 @@ impl IoHandler> for Host where Messa fn timeout(&self, io: &IoContext>, token: TimerToken) { match token { IDLE => self.maintain_network(io), - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io), + FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { self.discovery.lock().unwrap().refresh(); io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); @@ -782,7 +785,7 @@ impl IoHandler> for Host where Messa _ => match self.timers.read().unwrap().get(&token).cloned() { Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() { None => { warn!(target: "net", "No handler found for protocol: {:?}", timer.protocol) }, - Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.connections.clone()), timer.token); } + Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.sessions.clone()), timer.token); } }, None => { warn!("Unknown timer token: {}", token); } // timer is not registerd through us } @@ -797,7 +800,7 @@ impl IoHandler> for Host where Messa ref versions } => { let h = handler.clone(); - h.initialize(&NetworkContext::new(io, protocol, None, self.connections.clone())); + h.initialize(&NetworkContext::new(io, protocol, None, self.sessions.clone())); self.handlers.write().unwrap().insert(protocol, h); let mut info = self.info.write().unwrap(); for v in versions { @@ -820,18 +823,15 @@ impl IoHandler> for Host where Messa io.register_timer(handler_token, *delay).expect("Error registering timer"); }, NetworkIoMessage::Disconnect(ref peer) => { - let connection = { self.connections.read().unwrap().get(*peer).cloned() }; - if let Some(connection) = connection { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(_) => {}, - ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } - } + let session = { self.sessions.read().unwrap().get(*peer).cloned() }; + if let Some(session) = session { + session.lock().unwrap().disconnect(DisconnectReason::DisconnectRequested); } self.kill_connection(*peer, io, false); }, NetworkIoMessage::User(ref message) => { for (p, h) in self.handlers.read().unwrap().iter() { - h.message(&NetworkContext::new(io, p, None, self.connections.clone()), &message); + h.message(&NetworkContext::new(io, p, None, self.sessions.clone()), &message); } } } @@ -839,14 +839,14 @@ impl IoHandler> for Host where Messa fn register_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => { - let connection = { self.connections.read().unwrap().get(stream).cloned() }; + FIRST_SESSION ... LAST_SESSION => { + warn!("Unexpected session stream registration"); + } + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; if let Some(connection) = connection { - match *connection.lock().unwrap().deref() { - ConnectionEntry::Handshake(ref h) => h.register_socket(reg, event_loop).expect("Error registering socket"), - ConnectionEntry::Session(_) => warn!("Unexpected session stream registration") - } - } else {} // expired + connection.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); + } } DISCOVERY => self.discovery.lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), @@ -856,16 +856,20 @@ impl IoHandler> for Host where Messa fn deregister_stream(&self, stream: StreamToken, event_loop: &mut EventLoop>>) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => { - let mut connections = self.connections.write().unwrap(); + FIRST_SESSION ... LAST_SESSION => { + let mut connections = self.sessions.write().unwrap(); if let Some(connection) = connections.get(stream).cloned() { - match *connection.lock().unwrap().deref() { - ConnectionEntry::Handshake(ref h) => h.deregister_socket(event_loop).expect("Error deregistering socket"), - ConnectionEntry::Session(ref s) => s.deregister_socket(event_loop).expect("Error deregistering session socket"), - } + connection.lock().unwrap().deregister_socket(event_loop).expect("Error deregistering socket"); connections.remove(stream); - } - }, + } + } + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let mut connections = self.handshakes.write().unwrap(); + if let Some(connection) = connections.get(stream).cloned() { + connection.lock().unwrap().deregister_socket(event_loop).expect("Error deregistering socket"); + connections.remove(stream); + } + } DISCOVERY => (), TCP_ACCEPT => event_loop.deregister(self.tcp_listener.lock().unwrap().deref()).unwrap(), _ => warn!("Unexpected stream deregistration") @@ -874,14 +878,17 @@ impl IoHandler> for Host where Messa fn update_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => { - let connection = { self.connections.read().unwrap().get(stream).cloned() }; - if let Some(connection) = connection { - match *connection.lock().unwrap().deref() { - ConnectionEntry::Handshake(ref h) => h.update_socket(reg, event_loop).expect("Error updating socket"), - ConnectionEntry::Session(ref s) => s.update_socket(reg, event_loop).expect("Error updating socket"), - } - } else {} // expired + FIRST_SESSION ... LAST_SESSION => { + let connection = { self.sessions.read().unwrap().get(stream).cloned() }; + if let Some(connection) = connection { + connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); + } + } + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; + if let Some(connection) = connection { + connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); + } } DISCOVERY => self.discovery.lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 3b49a8f5e..2763dfd82 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -108,7 +108,7 @@ const PACKET_LAST: u8 = 0x7f; impl Session { /// Create a new session out of comepleted handshake. Consumes handshake object. - pub fn new(h: Handshake, _io: &IoContext, host: &HostInfo) -> Result where Message: Send + Sync + Clone { + pub fn new(h: Handshake, token: StreamToken, host: &HostInfo) -> Result { let id = h.id.clone(); let connection = try!(EncryptedConnection::new(h)); let mut session = Session { @@ -124,6 +124,7 @@ impl Session { ping_time_ns: 0, pong_time_ns: None, }; + session.connection.set_token(token); try!(session.write_hello(host)); try!(session.send_ping()); Ok(session) From 7503d6695a8ef22fa0aa4530745ceed95a260f63 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 11:54:08 +0100 Subject: [PATCH 012/753] Fixed panic on session creation --- util/src/network/host.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 04dda02bd..fe283e21a 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -635,7 +635,13 @@ impl Host where Message: Send + Sync + Clone { // turn a handshake into a session let mut sessions = self.sessions.write().unwrap(); - let h = handshakes.remove(token).unwrap(); + let mut h = handshakes.remove(token).unwrap(); + // wait for other threads to stop using it + { + while Arc::get_mut(&mut h).is_none() { + h.lock().ok(); + } + } let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap(); let result = sessions.insert_with(move |session_token| { let session = Session::new(h, session_token, &self.info.read().unwrap()).expect("Session creation error"); From dee375bfacc3010dadc97a8392f7f2d8632f8eac Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 12:11:18 +0100 Subject: [PATCH 013/753] Handle session creation error --- util/src/network/host.rs | 9 ++++++++- util/src/network/session.rs | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index fe283e21a..89cc4c225 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -643,8 +643,15 @@ impl Host where Message: Send + Sync + Clone { } } let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap(); + let mut session = match Session::new(h, &self.info.read().unwrap()) { + Ok(s) => s, + Err(e) => { + warn!("Session creation error: {:?}", e); + return; + } + }; let result = sessions.insert_with(move |session_token| { - let session = Session::new(h, session_token, &self.info.read().unwrap()).expect("Session creation error"); + session.set_token(session_token); io.update_registration(session_token).expect("Error updating session registration"); self.stats.inc_sessions(); Arc::new(Mutex::new(session)) diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 2763dfd82..f501e9c79 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -108,7 +108,7 @@ const PACKET_LAST: u8 = 0x7f; impl Session { /// Create a new session out of comepleted handshake. Consumes handshake object. - pub fn new(h: Handshake, token: StreamToken, host: &HostInfo) -> Result { + pub fn new(h: Handshake, host: &HostInfo) -> Result { let id = h.id.clone(); let connection = try!(EncryptedConnection::new(h)); let mut session = Session { @@ -124,7 +124,6 @@ impl Session { ping_time_ns: 0, pong_time_ns: None, }; - session.connection.set_token(token); try!(session.write_hello(host)); try!(session.send_ping()); Ok(session) @@ -140,6 +139,11 @@ impl Session { self.had_hello } + /// Replace socket token + pub fn set_token(&mut self, token: StreamToken) { + self.connection.set_token(token); + } + /// Readable IO handler. Returns packet data if available. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result where Message: Send + Sync + Clone { match try!(self.connection.readable(io)) { From fc7483ab87437e92751d676539eff93bcb774a7e Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 17:10:55 +0100 Subject: [PATCH 014/753] Propagate only one last hash for peers that are too far behind --- sync/src/chain.rs | 81 +++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 671e2241e..0de0bdcaf 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -155,7 +155,9 @@ struct PeerInfo { /// Peer network id network_id: U256, /// Peer best block hash - latest: H256, + latest_hash: H256, + /// Peer best block number if known + latest_number: Option, /// Peer total difficulty difficulty: U256, /// Type of data currenty being requested from peer. @@ -282,7 +284,8 @@ impl ChainSync { protocol_version: try!(r.val_at(0)), network_id: try!(r.val_at(1)), difficulty: try!(r.val_at(2)), - latest: try!(r.val_at(3)), + latest_hash: try!(r.val_at(3)), + latest_number: None, genesis: try!(r.val_at(4)), asking: PeerAsking::Nothing, asking_blocks: Vec::new(), @@ -290,7 +293,7 @@ impl ChainSync { ask_time: 0f64, }; - trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest, peer.genesis); + trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest_hash, peer.genesis); if self.peers.contains_key(&peer_id) { warn!("Unexpected status packet from {}:{}", peer_id, io.peer_info(peer_id)); @@ -450,7 +453,8 @@ impl ChainSync { let mut unknown = false; { let peer = self.peers.get_mut(&peer_id).unwrap(); - peer.latest = header.hash(); + peer.latest_hash = header.hash(); + peer.latest_number = Some(header.number()); } // TODO: Decompose block and add to self.headers and self.bodies instead if header.number == From::from(self.current_base_block() + 1) { @@ -516,7 +520,8 @@ impl ChainSync { if d > max_height { trace!(target: "sync", "New unknown block hash {:?}", h); let peer = self.peers.get_mut(&peer_id).unwrap(); - peer.latest = h.clone(); + peer.latest_hash = h.clone(); + peer.latest_number = Some(d); max_height = d; } }, @@ -583,7 +588,7 @@ impl ChainSync { trace!(target: "sync", "Waiting for block queue"); return; } - (peer.latest.clone(), peer.difficulty.clone()) + (peer.latest_hash.clone(), peer.difficulty.clone()) }; let td = io.chain().chain_info().pending_total_difficulty; @@ -1117,25 +1122,28 @@ impl ChainSync { } /// returns peer ids that have less blocks than our chain - fn get_lagging_peers(&self, io: &SyncIo) -> Vec { + fn get_lagging_peers(&mut self, io: &SyncIo) -> Vec<(PeerId, BlockNumber)> { let chain = io.chain(); let chain_info = chain.chain_info(); let latest_hash = chain_info.best_block_hash; let latest_number = chain_info.best_block_number; - self.peers.iter().filter(|&(_, peer_info)| - match io.chain().block_status(BlockId::Hash(peer_info.latest.clone())) { + self.peers.iter_mut().filter_map(|(&id, ref mut peer_info)| + match io.chain().block_status(BlockId::Hash(peer_info.latest_hash.clone())) { BlockStatus::InChain => { - let peer_number = HeaderView::new(&io.chain().block_header(BlockId::Hash(peer_info.latest.clone())).unwrap()).number(); - peer_info.latest != latest_hash && latest_number > peer_number + if peer_info.latest_number.is_none() { + peer_info.latest_number = Some(HeaderView::new(&io.chain().block_header(BlockId::Hash(peer_info.latest_hash.clone())).unwrap()).number()); + } + if peer_info.latest_hash != latest_hash && latest_number > peer_info.latest_number.unwrap() { + Some((id, peer_info.latest_number.unwrap())) + } else { None } }, - _ => false + _ => None }) - .map(|(peer_id, _)| peer_id) - .cloned().collect::>() + .collect::>() } /// propagades latest block to lagging peers - fn propagade_blocks(&mut self, local_best: &H256, io: &mut SyncIo) -> usize { + fn propagade_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { let updated_peers = { let lagging_peers = self.get_lagging_peers(io); @@ -1143,33 +1151,41 @@ impl ChainSync { let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32; let lucky_peers = match lagging_peers.len() { 0 ... MIN_PEERS_PROPAGATION => lagging_peers, - _ => lagging_peers.iter().filter(|_| ::rand::random::() < fraction).cloned().collect::>() + _ => lagging_peers.into_iter().filter(|_| ::rand::random::() < fraction).collect::>() }; // taking at max of MAX_PEERS_PROPAGATION - lucky_peers.iter().take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).cloned().collect::>() + lucky_peers.iter().map(|&(id, _)| id.clone()).take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::>() }; let mut sent = 0; for peer_id in updated_peers { let rlp = ChainSync::create_latest_block_rlp(io.chain()); self.send_packet(io, peer_id, NEW_BLOCK_PACKET, rlp); - self.peers.get_mut(&peer_id).unwrap().latest = local_best.clone(); + self.peers.get_mut(&peer_id).unwrap().latest_hash = local_best.clone(); + self.peers.get_mut(&peer_id).unwrap().latest_number = Some(best_number); sent = sent + 1; } sent } /// propagades new known hashes to all peers - fn propagade_new_hashes(&mut self, local_best: &H256, io: &mut SyncIo) -> usize { + fn propagade_new_hashes(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { let updated_peers = self.get_lagging_peers(io); let mut sent = 0; - for peer_id in updated_peers { - sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &self.peers.get(&peer_id).unwrap().latest, &local_best) { + let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(local_best.clone())).unwrap()).parent_hash(); + for (peer_id, peer_number) in updated_peers { + let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone(); + if best_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber { + // If we think peer is too far behind just end one latest hash + peer_best = last_parent.clone(); + } + sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &local_best) { Some(rlp) => { { let peer = self.peers.get_mut(&peer_id).unwrap(); - peer.latest = local_best.clone(); + peer.latest_hash = local_best.clone(); + peer.latest_number = Some(best_number); } self.send_packet(io, peer_id, NEW_BLOCK_HASHES_PACKET, rlp); 1 @@ -1189,8 +1205,8 @@ impl ChainSync { pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) { let chain = io.chain().chain_info(); if (((chain.best_block_number as i64) - (self.last_send_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let blocks = self.propagade_blocks(&chain.best_block_hash, io); - let hashes = self.propagade_new_hashes(&chain.best_block_hash, io); + let blocks = self.propagade_blocks(&chain.best_block_hash, chain.best_block_number, io); + let hashes = self.propagade_new_hashes(&chain.best_block_hash, chain.best_block_number, io); if blocks != 0 || hashes != 0 { trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); } @@ -1322,7 +1338,8 @@ mod tests { protocol_version: 0, genesis: H256::zero(), network_id: U256::zero(), - latest: peer_latest_hash, + latest_hash: peer_latest_hash, + latest_number: None, difficulty: U256::zero(), asking: PeerAsking::Nothing, asking_blocks: Vec::::new(), @@ -1337,7 +1354,7 @@ mod tests { let mut client = TestBlockChainClient::new(); client.add_blocks(100, false); let mut queue = VecDeque::new(); - let sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); let io = TestIo::new(&mut client, &mut queue, None); let lagging_peers = sync.get_lagging_peers(&io); @@ -1369,9 +1386,10 @@ mod tests { let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); + let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - let peer_count = sync.propagade_new_hashes(&best_hash, &mut io); + let peer_count = sync.propagade_new_hashes(&best_hash, best_number, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1388,9 +1406,10 @@ mod tests { let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); + let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - let peer_count = sync.propagade_blocks(&best_hash, &mut io); + let peer_count = sync.propagade_blocks(&best_hash, best_number, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1493,9 +1512,10 @@ mod tests { let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); + let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagade_new_hashes(&best_hash, &mut io); + sync.propagade_new_hashes(&best_hash, best_number, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(&data)); @@ -1511,9 +1531,10 @@ mod tests { let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); + let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagade_blocks(&best_hash, &mut io); + sync.propagade_blocks(&best_hash, best_number, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); From 61c52f15a3a2b81d718993668ba1a0a31e980ad2 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 17:42:03 +0100 Subject: [PATCH 015/753] Fixed panic on accessing expired node --- util/src/network/host.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 89cc4c225..454e8e802 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -82,7 +82,7 @@ impl NetworkConfiguration { pin: false, boot_nodes: Vec::new(), use_secret: None, - ideal_peers: 10, + ideal_peers: 25, } } @@ -467,9 +467,10 @@ impl Host where Message: Send + Sync + Clone { let socket = { let address = { let mut nodes = self.nodes.write().unwrap(); - let node = nodes.get_mut(id).unwrap(); - node.last_attempted = Some(::time::now()); - node.endpoint.address + if let Some(node) = nodes.get_mut(id) { + node.last_attempted = Some(::time::now()); + node.endpoint.address + } }; match TcpStream::connect(&address) { Ok(socket) => socket, From 38f4a06f1d248125e75ee07675a88a04f4d85617 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Feb 2016 17:45:00 +0100 Subject: [PATCH 016/753] Fixed panic on accessing expired node --- util/src/network/host.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 454e8e802..7366e129b 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -471,6 +471,10 @@ impl Host where Message: Send + Sync + Clone { node.last_attempted = Some(::time::now()); node.endpoint.address } + else { + debug!("Connection to expired node aborted"); + return; + } }; match TcpStream::connect(&address) { Ok(socket) => socket, @@ -647,7 +651,7 @@ impl Host where Message: Send + Sync + Clone { let mut session = match Session::new(h, &self.info.read().unwrap()) { Ok(s) => s, Err(e) => { - warn!("Session creation error: {:?}", e); + debug!("Session creation error: {:?}", e); return; } }; From bae268251896a22696ad0a765e1ae02850b204df Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 11:47:51 +0100 Subject: [PATCH 017/753] bloom possibilities --- rpc/src/v1/types/filter.rs | 113 ++++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 27 deletions(-) diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index cac1f7ef9..62b865bee 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -57,7 +57,7 @@ pub struct Filter { } impl Filter { - /// Returns combinations of each of address topic. + /// Returns combinations of each address and topic. pub fn bloom_possibilities(&self) -> Vec { let blooms = match self.address { Some(VariadicValue::Single(ref address)) => { @@ -77,33 +77,21 @@ impl Filter { match self.topics { None => blooms, - Some(ref topics) => blooms.into_iter().map(|bloom| { - //for topic in topics { - //match topic { - //VariadicValue::Single => { - //bloom.shift_bloomed(&topic.sha3()); - //bloom - //} - //} - //} - }).collect() + Some(ref topics) => topics.iter().fold(blooms, | bs, topic | match *topic { + VariadicValue::Null => bs, + VariadicValue::Single(ref topic) => bs.into_iter().map(|mut bloom| { + bloom.shift_bloomed(&topic.sha3()); + bloom + }).collect(), + VariadicValue::Multiple(ref topics) => bs.into_iter().map(|bloom| { + topics.into_iter().map(|topic| { + let mut b = bloom.clone(); + b.shift_bloomed(&topic.sha3()); + b + }).collect::>() + }).flat_map(|m| m).collect::>() + }) } - //self.address.as_ref().map(|a| match *a { - //VariadicValue::Single(ref address) => { - //let mut bloom = H2048::new(); - //bloom.shift_bloomed(&address.sha3()); - //vec![bloom] - //}, - //VariadicValue::Multiple(ref addresses) => { - //addresses.iter().map(|ref address| { - //let mut bloom = H2048::new(); - //bloom.shift_bloomed(&address.sha3()); - //bloom - //}).collect() - //}, - //VariadicValue::Null => vec![H2048::new()] - //}.into_iter().map(|bloom| match self. { - //}).unwrap_or_else(Vec::new) } } @@ -140,4 +128,75 @@ mod tests { topics: None }); } + + #[test] + fn test_bloom_possibilities_none() { + let none_filter = Filter { + from_block: None, + to_block: None, + address: None, + topics: None + }; + + let possibilities = none_filter.bloom_possibilities(); + assert_eq!(possibilities, vec![H2048::new()]); + } + + // block 399849 + #[test] + fn test_bloom_possibilities_single_address_and_topic() { + let filter = Filter { + from_block: None, + to_block: None, + address: Some(VariadicValue::Single(Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap())), + topics: Some(vec![VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap())]) + }; + + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); + } + + #[test] + fn test_bloom_possibilities_single_address_and_many_topics() { + let filter = Filter { + from_block: None, + to_block: None, + address: Some(VariadicValue::Single(Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap())), + topics: Some(vec![ + VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()), + VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()) + ]) + }; + + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); + } + + #[test] + fn test_bloom_possibilites_multiple_addresses_and_topics() { + let filter = Filter { + from_block: None, + to_block: None, + address: Some(VariadicValue::Multiple(vec![ + Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap() + ])), + topics: Some(vec![ + VariadicValue::Multiple(vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() + ]), + VariadicValue::Multiple(vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() + ]), + VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()) + ]) + }; + + // number of possibilites should be equal 2 * 2 * 2 * 1 = 8 + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities.len(), 8); + assert_eq!(possibilities[0], H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()); + } } From 186c7585d287a770ca0f45ed4f664e75093ff9b1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 11:54:38 +0100 Subject: [PATCH 018/753] Node table persistency --- util/src/bytes.rs | 4 +- util/src/hash.rs | 7 +++ util/src/io/service.rs | 5 ++ util/src/network/discovery.rs | 2 +- util/src/network/node_table.rs | 111 ++++++++++++++++++++++++++++++++- util/src/sha3.rs | 2 +- 6 files changed, 124 insertions(+), 7 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 4923e6eb4..4e1a11e4d 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -170,8 +170,8 @@ pub trait BytesConvertable { fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() } } -impl BytesConvertable for T where T: Deref { - fn bytes(&self) -> &[u8] { self.deref() } +impl BytesConvertable for T where T: AsRef<[u8]> { + fn bytes(&self) -> &[u8] { self.as_ref() } } #[test] diff --git a/util/src/hash.rs b/util/src/hash.rs index 3e164098b..aefa7795b 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -86,6 +86,13 @@ macro_rules! impl_hash { } } + impl AsRef<[u8]> for $from { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + impl DerefMut for $from { #[inline] fn deref_mut(&mut self) -> &mut [u8] { diff --git a/util/src/io/service.rs b/util/src/io/service.rs index c5f4a6072..83fa71b8a 100644 --- a/util/src/io/service.rs +++ b/util/src/io/service.rs @@ -256,6 +256,11 @@ impl Handler for IoManager where Message: Send + Clone + Sync IoMessage::DeregisterStream { handler_id, token } => { let handler = self.handlers.get(handler_id).expect("Unknown handler id").clone(); handler.deregister_stream(token, event_loop); + // unregister a timer associated with the token (if any) + let timer_id = token + handler_id * TOKENS_PER_HANDLER; + if let Some(timer) = self.timers.write().unwrap().remove(&timer_id) { + event_loop.clear_timeout(timer.timeout); + } }, IoMessage::UpdateStreamRegistration { handler_id, token } => { let handler = self.handlers.get(handler_id).expect("Unknown handler id").clone(); diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 9feef9c74..04c32cd33 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -209,7 +209,7 @@ impl Discovery { rlp.append(×tamp); let bytes = rlp.drain(); - let hash = bytes.sha3(); + let hash = bytes.as_ref().sha3(); let signature = match ec::sign(&self.secret, &hash) { Ok(s) => s, Err(_) => { diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index a3ee57481..dea18ab63 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -20,11 +20,17 @@ use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, use std::hash::{Hash, Hasher}; use std::str::{FromStr}; use std::collections::HashMap; +use std::fmt::{Display, Formatter}; +use std::path::{PathBuf, Path}; +use std::fmt; +use std::fs; +use std::io::{Read, Write}; use hash::*; use rlp::*; use time::Tm; use error::*; use network::discovery::TableUpdates; +pub use rustc_serialize::json::Json; /// Node public key pub type NodeId = H512; @@ -135,6 +141,17 @@ impl Node { } } +impl Display for Node { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.endpoint.udp_port != self.endpoint.address.port() { + write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port); + } else { + write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address); + } + Ok(()) + } +} + impl FromStr for Node { type Err = UtilError; fn from_str(s: &str) -> Result { @@ -170,13 +187,15 @@ impl Hash for Node { /// Node table backed by disk file. pub struct NodeTable { - nodes: HashMap + nodes: HashMap, + path: Option, } impl NodeTable { - pub fn new(_path: Option) -> NodeTable { + pub fn new(path: Option) -> NodeTable { NodeTable { - nodes: HashMap::new() + path: path.clone(), + nodes: NodeTable::load(path), } } @@ -208,11 +227,86 @@ impl NodeTable { } } + /// Increase failure counte for a node pub fn note_failure(&mut self, id: &NodeId) { if let Some(node) = self.nodes.get_mut(id) { node.failures += 1; } } + + fn save(&self) { + if let Some(ref path) = self.path { + let mut path_buf = PathBuf::from(path); + path_buf.push("nodes.json"); + let mut json = String::new(); + json.push_str("{\n"); + json.push_str("nodes: [\n"); + let node_ids = self.nodes(); + for i in 0 .. node_ids.len() { + let node = self.nodes.get(&node_ids[i]).unwrap(); + json.push_str(&format!("\t{{ url: \"{}\", failures: {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) + } + json.push_str("]\n"); + json.push_str("}"); + let mut file = match fs::File::create(path_buf.as_path()) { + Ok(file) => file, + Err(e) => { + warn!("Error creating node table file: {:?}", e); + return; + } + }; + if let Err(e) = file.write(&json.into_bytes()) { + warn!("Error writing node table file: {:?}", e); + } + } + } + + fn load(path: Option) -> HashMap { + let mut nodes: HashMap = HashMap::new(); + if let Some(path) = path { + let mut file = match fs::File::open(path.clone()) { + Ok(file) => file, + Err(e) => { + warn!("Error opening node table file: {:?}", e); + return nodes; + } + }; + let mut buf = String::new(); + match file.read_to_string(&mut buf) { + Ok(_) => {}, + Err(e) => { + warn!("Error reading node table file: {:?}", e); + return nodes; + } + } + let json = match Json::from_str(&buf) { + Ok(json) => json, + Err(e) => { + warn!("Error parsing node table file: {:?}", e); + return nodes; + } + }; + if let Some(list) = json.as_object().and_then(|o| o.get("nodes")).and_then(|n| n.as_array()) { + for n in list.iter().filter_map(|n| n.as_object()) { + if let Some(url) = n.get("url").and_then(|u| u.as_string()) { + if let Ok(mut node) = Node::from_str(url) { + if let Some(failures) = n.get("failures").and_then(|f| f.as_u64()) { + node.failures = failures as u32; + } + nodes.insert(node.id.clone(), node); + } + } + } + } + } + nodes + } +} + +impl Drop for NodeTable { + fn drop(&mut self) { + self.save(); + } } #[cfg(test)] @@ -247,4 +341,15 @@ mod tests { H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(), node.id); } + + #[test] + fn table_failure_order() { + let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); + let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); + let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); + let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id3 = H512::from_str("3979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let mut table = NodeTable::new(None); + } } diff --git a/util/src/sha3.rs b/util/src/sha3.rs index 7e8382250..4079e8ba4 100644 --- a/util/src/sha3.rs +++ b/util/src/sha3.rs @@ -66,7 +66,7 @@ impl Hashable for T where T: BytesConvertable { #[test] fn sha3_empty() { - assert_eq!([0u8; 0].sha3(), SHA3_EMPTY); + assert_eq!((&[0u8; 0]).sha3(), SHA3_EMPTY); } #[test] fn sha3_as() { From fada9bb1baf3f63553535a4f5e96b1cf1a79c65e Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 13:18:26 +0100 Subject: [PATCH 019/753] eth_getLogs implementation --- rpc/src/v1/impls/eth.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index b595139f9..85afdd612 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . //! Eth rpc implementation. +use std::collections::HashSet; use std::sync::Arc; use ethsync::{EthSync, SyncState}; use jsonrpc_core::*; @@ -25,7 +26,7 @@ use ethcore::client::*; use ethcore::views::*; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter}; /// Eth rpc implementation. pub struct EthClient { @@ -197,6 +198,21 @@ impl Eth for EthClient { from_params::<(BlockNumber, Index)>(params) .and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value()))) } + + fn logs(&self, params: Params) -> Result { + from_params::<(Filter,)>(params) + .and_then(|(filter,)| { + let possibilities = filter.bloom_possibilities(); + let from = filter.from_block.map_or_else(|| BlockId::Earliest, Into::into); + let to = filter.to_block.map_or_else(|| BlockId::Latest, Into::into); + let blocks: HashSet = possibilities.iter() + .map(|bloom| self.client.blocks_with_bloom(bloom, from.clone(), to.clone())) + .filter_map(|m| m) + .flat_map(|m| m) + .collect(); + to_value(&blocks) + }) + } } From 8b28f627caebbc214363886b9e8f1315ea87f2ec Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 13:39:58 +0100 Subject: [PATCH 020/753] fixed order of eth_getLogs --- rpc/src/v1/impls/eth.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 85afdd612..bbeb475dc 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -205,11 +205,14 @@ impl Eth for EthClient { let possibilities = filter.bloom_possibilities(); let from = filter.from_block.map_or_else(|| BlockId::Earliest, Into::into); let to = filter.to_block.map_or_else(|| BlockId::Latest, Into::into); - let blocks: HashSet = possibilities.iter() + let mut blocks: Vec = possibilities.iter() .map(|bloom| self.client.blocks_with_bloom(bloom, from.clone(), to.clone())) .filter_map(|m| m) .flat_map(|m| m) + .collect::>() + .into_iter() .collect(); + blocks.sort(); to_value(&blocks) }) } From cf45d5914a3e355210f4fad7744d00c8e7b7976a Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 14:39:56 +0100 Subject: [PATCH 021/753] Node table tests --- util/src/network/discovery.rs | 2 +- util/src/network/mod.rs | 2 +- util/src/network/node_table.rs | 95 ++++++++++++++++++++++++++++++---- util/src/network/tests.rs | 2 +- 4 files changed, 88 insertions(+), 13 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 04c32cd33..c580c8507 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -254,7 +254,7 @@ impl Discovery { } let mut ret:Vec = Vec::new(); - for (_, nodes) in found { + for nodes in found.values() { ret.extend(nodes.iter().map(|&n| n.clone())); } ret diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index 7d5aac8f7..c5066ff99 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -56,7 +56,7 @@ //! } //! //! fn main () { -//! let mut service = NetworkService::::start(NetworkConfiguration::new()).expect("Error creating network service"); +//! let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40412)).expect("Error creating network service"); //! service.register_protocol(Arc::new(MyHandler), "myproto", &[1u8]); //! //! // Wait for quit condition diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index dea18ab63..2b02748b4 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -21,7 +21,7 @@ use std::hash::{Hash, Hasher}; use std::str::{FromStr}; use std::collections::HashMap; use std::fmt::{Display, Formatter}; -use std::path::{PathBuf, Path}; +use std::path::{PathBuf}; use std::fmt; use std::fs; use std::io::{Read, Write}; @@ -144,9 +144,9 @@ impl Node { impl Display for Node { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if self.endpoint.udp_port != self.endpoint.address.port() { - write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port); + try!(write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port)); } else { - write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address); + try!(write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address)); } Ok(()) } @@ -237,14 +237,18 @@ impl NodeTable { fn save(&self) { if let Some(ref path) = self.path { let mut path_buf = PathBuf::from(path); + if let Err(e) = fs::create_dir_all(path_buf.as_path()) { + warn!("Error creating node table directory: {:?}", e); + return; + }; path_buf.push("nodes.json"); let mut json = String::new(); json.push_str("{\n"); - json.push_str("nodes: [\n"); + json.push_str("\"nodes\": [\n"); let node_ids = self.nodes(); for i in 0 .. node_ids.len() { let node = self.nodes.get(&node_ids[i]).unwrap(); - json.push_str(&format!("\t{{ url: \"{}\", failures: {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) + json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) } json.push_str("]\n"); json.push_str("}"); @@ -264,7 +268,9 @@ impl NodeTable { fn load(path: Option) -> HashMap { let mut nodes: HashMap = HashMap::new(); if let Some(path) = path { - let mut file = match fs::File::open(path.clone()) { + let mut path_buf = PathBuf::from(path); + path_buf.push("nodes.json"); + let mut file = match fs::File::open(path_buf.as_path()) { Ok(file) => file, Err(e) => { warn!("Error opening node table file: {:?}", e); @@ -344,12 +350,81 @@ mod tests { #[test] fn table_failure_order() { - let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); - let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); - let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); + let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); - let id3 = H512::from_str("3979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let mut table = NodeTable::new(None); + table.add_node(node3); + table.add_node(node1); + table.add_node(node2); + + table.note_failure(&id1); + table.note_failure(&id1); + table.note_failure(&id2); + + let r = table.nodes(); + assert_eq!(r[0][..], id3[..]); + assert_eq!(r[1][..], id2[..]); + assert_eq!(r[2][..], id1[..]); + } + + use std::path::PathBuf; + use std::env; + use std::fs::{remove_dir_all}; + // TODO: use common impl + pub struct RandomTempPath { + path: PathBuf + } + + impl RandomTempPath { + pub fn new() -> RandomTempPath { + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + RandomTempPath { + path: dir.clone() + } + } + + pub fn as_path(&self) -> &PathBuf { + &self.path + } + + pub fn as_str(&self) -> &str { + self.path.to_str().unwrap() + } + } + + impl Drop for RandomTempPath { + fn drop(&mut self) { + if let Err(e) = remove_dir_all(self.as_path()) { + panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); + } + } + } + + + #[test] + fn table_save_load() { + let temp_path = RandomTempPath::new(); + let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + { + let mut table = NodeTable::new(Some(temp_path.as_str().to_owned())); + table.add_node(node1); + table.add_node(node2); + table.note_failure(&id2); + } + + { + let table = NodeTable::new(Some(temp_path.as_str().to_owned())); + let r = table.nodes(); + assert_eq!(r[0][..], id1[..]); + assert_eq!(r[1][..], id2[..]); + } } } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index c1b59df9b..a3d5290c9 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -85,7 +85,7 @@ impl NetworkProtocolHandler for TestProtocol { #[test] fn net_service() { - let mut service = NetworkService::::start(NetworkConfiguration::new()).expect("Error creating network service"); + let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40414)).expect("Error creating network service"); service.register_protocol(Arc::new(TestProtocol::default()), "myproto", &[1u8]).unwrap(); } From 0fab166fbae75a46822e33f443810229313fd3cb Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 15:22:13 +0100 Subject: [PATCH 022/753] refactored chainfilter.rs, split out indexer --- ethcore/src/chainfilter/bloomindex.rs | 40 +++ ethcore/src/{ => chainfilter}/chainfilter.rs | 287 ++----------------- ethcore/src/chainfilter/indexer.rs | 154 ++++++++++ ethcore/src/chainfilter/mod.rs | 35 +++ ethcore/src/chainfilter/tests.rs | 95 ++++++ 5 files changed, 351 insertions(+), 260 deletions(-) create mode 100644 ethcore/src/chainfilter/bloomindex.rs rename ethcore/src/{ => chainfilter}/chainfilter.rs (51%) create mode 100644 ethcore/src/chainfilter/indexer.rs create mode 100644 ethcore/src/chainfilter/mod.rs create mode 100644 ethcore/src/chainfilter/tests.rs diff --git a/ethcore/src/chainfilter/bloomindex.rs b/ethcore/src/chainfilter/bloomindex.rs new file mode 100644 index 000000000..22785495e --- /dev/null +++ b/ethcore/src/chainfilter/bloomindex.rs @@ -0,0 +1,40 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Represents bloom index in cache + +/// Represents bloom index in cache +/// +/// On cache level 0, every block bloom is represented by different index. +/// On higher cache levels, multiple block blooms are represented by one +/// index. Their `BloomIndex` can be created from block number and given level. +#[derive(Eq, PartialEq, Hash, Clone, Debug)] +pub struct BloomIndex { + /// Bloom level + pub level: u8, + /// Filter Index + pub index: usize, +} + +impl BloomIndex { + /// Default constructor for `BloomIndex` + pub fn new(level: u8, index: usize) -> BloomIndex { + BloomIndex { + level: level, + index: index, + } + } +} diff --git a/ethcore/src/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs similarity index 51% rename from ethcore/src/chainfilter.rs rename to ethcore/src/chainfilter/chainfilter.rs index 95bac64e3..edfe85d67 100644 --- a/ethcore/src/chainfilter.rs +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -58,70 +58,15 @@ use std::collections::{HashMap}; use util::hash::*; use util::sha3::*; - -/// Represents bloom index in cache -/// -/// On cache level 0, every block bloom is represented by different index. -/// On higher cache levels, multiple block blooms are represented by one -/// index. Their `BloomIndex` can be created from block number and given level. -#[derive(Eq, PartialEq, Hash, Clone, Debug)] -pub struct BloomIndex { - /// Bloom level - pub level: u8, - /// Filter Index - pub index: usize, -} - -impl BloomIndex { - /// Default constructor for `BloomIndex` - pub fn new(level: u8, index: usize) -> BloomIndex { - BloomIndex { - level: level, - index: index, - } - } -} - -/// Types implementing this trait should provide read access for bloom filters database. -pub trait FilterDataSource { - /// returns reference to log at given position if it exists - fn bloom_at_index(&self, index: &BloomIndex) -> Option; -} - -/// In memory cache for blooms. -/// -/// Stores all blooms in HashMap, which indexes them by `BloomIndex`. -pub struct MemoryCache { - blooms: HashMap, -} - -impl MemoryCache { - /// Default constructor for MemoryCache - pub fn new() -> MemoryCache { - MemoryCache { blooms: HashMap::new() } - } - - /// inserts all blooms into cache - /// - /// if bloom at given index already exists, overwrites it - pub fn insert_blooms(&mut self, blooms: HashMap) { - self.blooms.extend(blooms); - } -} - -impl FilterDataSource for MemoryCache { - fn bloom_at_index(&self, index: &BloomIndex) -> Option { - self.blooms.get(index).cloned() - } -} +use chainfilter::{BloomIndex, FilterDataSource}; +use chainfilter::indexer::Indexer; /// Should be used for search operations on blockchain. pub struct ChainFilter<'a, D> where D: FilterDataSource + 'a { data_source: &'a D, - index_size: usize, - level_sizes: Vec, + indexer: Indexer } impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource @@ -130,73 +75,15 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource /// /// Borrows `FilterDataSource` for reading. pub fn new(data_source: &'a D, index_size: usize, levels: u8) -> Self { - if levels == 0 { - panic!("ChainFilter requires at least 1 level"); - } - - let mut filter = ChainFilter { + ChainFilter { data_source: data_source, - index_size: index_size, - // 0 level has always a size of 1 - level_sizes: vec![1] - }; - - // cache level sizes, so we do not have to calculate them all the time - // eg. if levels == 3, index_size = 16 - // level_sizes = [1, 16, 256] - let additional: Vec = (1..).into_iter() - .scan(1, |acc, _| { - *acc = *acc * index_size; - Some(*acc) - }) - .take(levels as usize - 1) - .collect(); - filter.level_sizes.extend(additional); - - filter - } - - /// unsafely get level size - fn level_size(&self, level: u8) -> usize { - self.level_sizes[level as usize] - } - - /// converts block number and level to `BloomIndex` - fn bloom_index(&self, block_number: usize, level: u8) -> BloomIndex { - BloomIndex { - level: level, - index: block_number / self.level_size(level), + indexer: Indexer::new(index_size, levels) } } - /// return bloom which are dependencies for given index - /// - /// bloom indexes are ordered from lowest to highest - fn lower_level_bloom_indexes(&self, index: &BloomIndex) -> Vec { - // this is the lowest level - if index.level == 0 { - return vec![]; - } - - let new_level = index.level - 1; - let offset = self.index_size * index.index; - - (0..self.index_size).map(|i| BloomIndex::new(new_level, offset + i)).collect() - } - - /// return number of levels - fn levels(&self) -> u8 { - self.level_sizes.len() as u8 - } - - /// returns max filter level - fn max_level(&self) -> u8 { - self.level_sizes.len() as u8 - 1 - } - /// internal function which does bloom search recursively fn blocks(&self, bloom: &H2048, from_block: usize, to_block: usize, level: u8, offset: usize) -> Option> { - let index = self.bloom_index(offset, level); + let index = self.indexer.bloom_index(offset, level); match self.data_source.bloom_at_index(&index) { None => return None, @@ -213,10 +100,10 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource } }; - let level_size = self.level_size(level - 1); - let from_index = self.bloom_index(from_block, level - 1); - let to_index = self.bloom_index(to_block, level - 1); - let res: Vec = self.lower_level_bloom_indexes(&index).into_iter() + let level_size = self.indexer.level_size(level - 1); + let from_index = self.indexer.bloom_index(from_block, level - 1); + let to_index = self.indexer.bloom_index(to_block, level - 1); + let res: Vec = self.indexer.lower_level_bloom_indexes(&index).into_iter() // chose only blooms in range .filter(|li| li.index >= from_index.index && li.index <= to_index.index) // map them to offsets @@ -235,8 +122,8 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource pub fn add_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap { let mut result: HashMap = HashMap::new(); - for level in 0..self.levels() { - let bloom_index = self.bloom_index(block_number, level); + for level in 0..self.indexer.levels() { + let bloom_index = self.indexer.bloom_index(block_number, level); let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { Some(old_bloom) => old_bloom | bloom.clone(), None => bloom.clone(), @@ -252,9 +139,9 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource pub fn add_blooms(&self, blooms: &[H2048], block_number: usize) -> HashMap { let mut result: HashMap = HashMap::new(); - for level in 0..self.levels() { + for level in 0..self.indexer.levels() { for i in 0..blooms.len() { - let bloom_index = self.bloom_index(block_number + i, level); + let bloom_index = self.indexer.bloom_index(block_number + i, level); let is_new_bloom = match result.get_mut(&bloom_index) { // it was already modified @@ -283,13 +170,13 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource pub fn reset_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap { let mut result: HashMap = HashMap::new(); - let mut reset_index = self.bloom_index(block_number, 0); + let mut reset_index = self.indexer.bloom_index(block_number, 0); result.insert(reset_index.clone(), bloom.clone()); - for level in 1..self.levels() { - let index = self.bloom_index(block_number, level); + for level in 1..self.indexer.levels() { + let index = self.indexer.bloom_index(block_number, level); // get all bloom indexes that were used to construct this bloom - let lower_indexes = self.lower_level_bloom_indexes(&index); + let lower_indexes = self.indexer.lower_level_bloom_indexes(&index); let new_bloom = lower_indexes.into_iter() // skip reseted one .filter(|li| li != &reset_index) @@ -313,23 +200,23 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource // insert all new blooms at level 0 for (i, bloom) in blooms.iter().enumerate() { - result.insert(self.bloom_index(block_number + i, 0), bloom.clone()); + result.insert(self.indexer.bloom_index(block_number + i, 0), bloom.clone()); } // reset the rest of blooms for reset_number in block_number + blooms.len()..old_highest_block { - result.insert(self.bloom_index(reset_number, 0), H2048::new()); + result.insert(self.indexer.bloom_index(reset_number, 0), H2048::new()); } - for level in 1..self.levels() { + for level in 1..self.indexer.levels() { for i in 0..blooms.len() { - let index = self.bloom_index(block_number + i, level); + let index = self.indexer.bloom_index(block_number + i, level); let new_bloom = { // use new blooms before db blooms where necessary let bloom_at = | index | { result.get(&index).cloned().or_else(|| self.data_source.bloom_at_index(&index)) }; - self.lower_level_bloom_indexes(&index) + self.indexer.lower_level_bloom_indexes(&index) .into_iter() // get blooms .map(bloom_at) @@ -369,10 +256,10 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource pub fn blocks_with_bloom(&self, bloom: &H2048, from_block: usize, to_block: usize) -> Vec { let mut result = vec![]; // lets start from highest level - let max_level = self.max_level(); - let level_size = self.level_size(max_level); - let from_index = self.bloom_index(from_block, max_level); - let to_index = self.bloom_index(to_block, max_level); + let max_level = self.indexer.max_level(); + let level_size = self.indexer.level_size(max_level); + let from_index = self.indexer.bloom_index(from_block, max_level); + let to_index = self.indexer.bloom_index(to_block, max_level); for index in from_index.index..to_index.index + 1 { // offset will be used to calculate where we are right now @@ -387,123 +274,3 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource result } } - -#[cfg(test)] -mod tests { - use std::str::FromStr; - use util::hash::*; - use chainfilter::*; - use util::sha3::*; - - #[test] - fn test_level_size() { - let cache = MemoryCache::new(); - let filter = ChainFilter::new(&cache, 16, 3); - assert_eq!(filter.level_size(0), 1); - assert_eq!(filter.level_size(1), 16); - assert_eq!(filter.level_size(2), 256); - } - - #[test] - fn test_bloom_index() { - let cache = MemoryCache::new(); - let filter = ChainFilter::new(&cache, 16, 3); - - let bi0 = filter.bloom_index(0, 0); - assert_eq!(bi0.level, 0); - assert_eq!(bi0.index, 0); - - let bi1 = filter.bloom_index(1, 0); - assert_eq!(bi1.level, 0); - assert_eq!(bi1.index, 1); - - let bi2 = filter.bloom_index(2, 0); - assert_eq!(bi2.level, 0); - assert_eq!(bi2.index, 2); - - let bi3 = filter.bloom_index(3, 1); - assert_eq!(bi3.level, 1); - assert_eq!(bi3.index, 0); - - let bi4 = filter.bloom_index(15, 1); - assert_eq!(bi4.level, 1); - assert_eq!(bi4.index, 0); - - let bi5 = filter.bloom_index(16, 1); - assert_eq!(bi5.level, 1); - assert_eq!(bi5.index, 1); - - let bi6 = filter.bloom_index(255, 2); - assert_eq!(bi6.level, 2); - assert_eq!(bi6.index, 0); - - let bi7 = filter.bloom_index(256, 2); - assert_eq!(bi7.level, 2); - assert_eq!(bi7.index, 1); - } - - #[test] - fn test_lower_level_bloom_indexes() { - let cache = MemoryCache::new(); - let filter = ChainFilter::new(&cache, 16, 3); - - let bi = filter.bloom_index(256, 2); - assert_eq!(bi.level, 2); - assert_eq!(bi.index, 1); - - let mut ebis = vec![]; - for i in 16..32 { - ebis.push(BloomIndex::new(1, i)); - } - - let bis = filter.lower_level_bloom_indexes(&bi); - assert_eq!(ebis, bis); - } - - #[test] - fn test_topic_basic_search() { - let index_size = 16; - let bloom_levels = 3; - - let mut cache = MemoryCache::new(); - let topic = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba").unwrap(); - - let modified_blooms = { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let block_number = 23; - let mut bloom = H2048::new(); - bloom.shift_bloomed(&topic.sha3()); - filter.add_bloom(&bloom, block_number) - }; - - // number of modified blooms should always be equal number of levels - assert_eq!(modified_blooms.len(), bloom_levels as usize); - cache.insert_blooms(modified_blooms); - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 0, 100); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], 23); - } - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 0, 23); - assert_eq!(blocks.len(), 0); - } - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 23, 24); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], 23); - } - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 24, 100); - assert_eq!(blocks.len(), 0); - } - } -} diff --git a/ethcore/src/chainfilter/indexer.rs b/ethcore/src/chainfilter/indexer.rs new file mode 100644 index 000000000..141a4e7d3 --- /dev/null +++ b/ethcore/src/chainfilter/indexer.rs @@ -0,0 +1,154 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Simplifies working with bloom indexes. + +use chainfilter::BloomIndex; + +/// Simplifies working with bloom indexes. +pub struct Indexer { + index_size: usize, + level_sizes: Vec +} + +impl Indexer { + /// Creates new indexer. + pub fn new(index_size: usize, levels: u8) -> Self { + if levels == 0 { + panic!("Indexer requires at least 1 level."); + } + + let mut level_sizes = vec![1]; + level_sizes.extend_from_slice(&(1..).into_iter() + .scan(1, |acc, _| { + *acc = *acc * index_size; + Some(*acc) + }) + .take(levels as usize - 1) + .collect::>()); + + Indexer { + index_size: index_size, + level_sizes: level_sizes, + } + } + + /// unsafely get level size. + pub fn level_size(&self, level: u8) -> usize { + self.level_sizes[level as usize] + } + + /// Converts block number and level to `BloomIndex`. + pub fn bloom_index(&self, block_number: usize, level: u8) -> BloomIndex { + BloomIndex { + level: level, + index: block_number / self.level_size(level), + } + } + + /// Return bloom which are dependencies for given index. + /// + /// Bloom indexes are ordered from lowest to highest. + pub fn lower_level_bloom_indexes(&self, index: &BloomIndex) -> Vec { + // this is the lowest level + if index.level == 0 { + return vec![]; + } + + let new_level = index.level - 1; + let offset = self.index_size * index.index; + + (0..self.index_size).map(|i| BloomIndex::new(new_level, offset + i)).collect() + } + + /// Return number of levels. + pub fn levels(&self) -> u8 { + self.level_sizes.len() as u8 + } + + /// Returns max indexer level. + pub fn max_level(&self) -> u8 { + self.level_sizes.len() as u8 - 1 + } +} + +#[cfg(test)] +mod tests { + use chainfilter::BloomIndex; + use chainfilter::indexer::Indexer; + + #[test] + fn test_level_size() { + let indexer = Indexer::new(16, 3); + assert_eq!(indexer.level_size(0), 1); + assert_eq!(indexer.level_size(1), 16); + assert_eq!(indexer.level_size(2), 256); + } + + #[test] + fn test_bloom_index() { + let indexer = Indexer::new(16, 3); + + let bi0 = indexer.bloom_index(0, 0); + assert_eq!(bi0.level, 0); + assert_eq!(bi0.index, 0); + + let bi1 = indexer.bloom_index(1, 0); + assert_eq!(bi1.level, 0); + assert_eq!(bi1.index, 1); + + let bi2 = indexer.bloom_index(2, 0); + assert_eq!(bi2.level, 0); + assert_eq!(bi2.index, 2); + + let bi3 = indexer.bloom_index(3, 1); + assert_eq!(bi3.level, 1); + assert_eq!(bi3.index, 0); + + let bi4 = indexer.bloom_index(15, 1); + assert_eq!(bi4.level, 1); + assert_eq!(bi4.index, 0); + + let bi5 = indexer.bloom_index(16, 1); + assert_eq!(bi5.level, 1); + assert_eq!(bi5.index, 1); + + let bi6 = indexer.bloom_index(255, 2); + assert_eq!(bi6.level, 2); + assert_eq!(bi6.index, 0); + + let bi7 = indexer.bloom_index(256, 2); + assert_eq!(bi7.level, 2); + assert_eq!(bi7.index, 1); + } + + #[test] + fn test_lower_level_bloom_indexes() { + let indexer = Indexer::new(16, 3); + + let bi = indexer.bloom_index(256, 2); + assert_eq!(bi.level, 2); + assert_eq!(bi.index, 1); + + let mut ebis = vec![]; + for i in 16..32 { + ebis.push(BloomIndex::new(1, i)); + } + + let bis = indexer.lower_level_bloom_indexes(&bi); + assert_eq!(ebis, bis); + } +} diff --git a/ethcore/src/chainfilter/mod.rs b/ethcore/src/chainfilter/mod.rs new file mode 100644 index 000000000..d85fc20f9 --- /dev/null +++ b/ethcore/src/chainfilter/mod.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Multilevel blockchain bloom filter. + +mod bloomindex; +mod chainfilter; +mod indexer; + +#[cfg(test)] +mod tests; + +pub use self::bloomindex::BloomIndex; +pub use self::chainfilter::ChainFilter; +use util::hash::H2048; + +/// Types implementing this trait provide read access for bloom filters database. +pub trait FilterDataSource { + /// returns reference to log at given position if it exists + fn bloom_at_index(&self, index: &BloomIndex) -> Option; +} + diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs new file mode 100644 index 000000000..2c1f6e298 --- /dev/null +++ b/ethcore/src/chainfilter/tests.rs @@ -0,0 +1,95 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashMap; +use std::str::FromStr; +use util::hash::*; +use util::sha3::*; +use chainfilter::{BloomIndex, FilterDataSource, ChainFilter}; + +/// In memory cache for blooms. +/// +/// Stores all blooms in HashMap, which indexes them by `BloomIndex`. +pub struct MemoryCache { + blooms: HashMap, +} + +impl MemoryCache { + /// Default constructor for MemoryCache + pub fn new() -> MemoryCache { + MemoryCache { blooms: HashMap::new() } + } + + /// inserts all blooms into cache + /// + /// if bloom at given index already exists, overwrites it + pub fn insert_blooms(&mut self, blooms: HashMap) { + self.blooms.extend(blooms); + } +} + +impl FilterDataSource for MemoryCache { + fn bloom_at_index(&self, index: &BloomIndex) -> Option { + self.blooms.get(index).cloned() + } +} + +#[test] +fn test_topic_basic_search() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + let topic = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba").unwrap(); + + let modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 23; + let mut bloom = H2048::new(); + bloom.shift_bloomed(&topic.sha3()); + filter.add_bloom(&bloom, block_number) + }; + + // number of modified blooms should always be equal number of levels + assert_eq!(modified_blooms.len(), bloom_levels as usize); + cache.insert_blooms(modified_blooms); + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_topic(&topic, 0, 100); + assert_eq!(blocks.len(), 1); + assert_eq!(blocks[0], 23); + } + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_topic(&topic, 0, 23); + assert_eq!(blocks.len(), 0); + } + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_topic(&topic, 23, 24); + assert_eq!(blocks.len(), 1); + assert_eq!(blocks[0], 23); + } + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_topic(&topic, 24, 100); + assert_eq!(blocks.len(), 0); + } +} From 552fe1fb4b3cc80742e1cf01a77e12501d25ce57 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 15:42:43 +0100 Subject: [PATCH 023/753] removed unused functions and warnings --- ethcore/src/blockchain.rs | 7 +- ethcore/src/chainfilter/chainfilter.rs | 89 ++------------------------ ethcore/src/chainfilter/tests.rs | 18 ++++-- ethcore/src/verification.rs | 2 +- 4 files changed, 19 insertions(+), 97 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index ef6090a53..68d677703 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -484,7 +484,7 @@ impl BlockChain { /// Transforms block into WriteBatch that may be written into database /// Additionally, if it's new best block it returns new best block object. - fn block_to_extras_insert_batch(&self, bytes: &[u8], receipts: &[Receipt]) -> (WriteBatch, Option, BlockDetails) { + fn block_to_extras_insert_batch(&self, bytes: &[u8], _receipts: &[Receipt]) -> (WriteBatch, Option, BlockDetails) { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -616,11 +616,6 @@ impl BlockChain { self.best_block.read().unwrap().total_difficulty } - /// Get the transactions' log blooms of a block. - fn log_blooms(&self, hash: &H256) -> Option { - self.query_extras(hash, &self.block_logs) - } - /// Get block blooms. fn blocks_blooms(&self, hash: &H256) -> Option { self.query_extras(hash, &self.blocks_blooms) diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs index edfe85d67..ab27f77ff 100644 --- a/ethcore/src/chainfilter/chainfilter.rs +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -57,7 +57,6 @@ //! use std::collections::{HashMap}; use util::hash::*; -use util::sha3::*; use chainfilter::{BloomIndex, FilterDataSource}; use chainfilter::indexer::Indexer; @@ -89,10 +88,12 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource None => return None, Some(level_bloom) => match level { // if we are on the lowest level - // take the value, exclude to_block - 0 if offset < to_block => return Some(vec![offset]), - // return None if it is is equal to to_block - 0 => return None, + 0 => return match offset < to_block { + // take the value if its smaller than to_block + true => Some(vec![offset]), + // return None if it is is equal to to_block + false => None + }, // return None if current level doesnt contain given bloom _ if !level_bloom.contains(bloom) => return None, // continue processing && go down @@ -135,65 +136,6 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource result } - /// Adds new blooms starting from block number. - pub fn add_blooms(&self, blooms: &[H2048], block_number: usize) -> HashMap { - let mut result: HashMap = HashMap::new(); - - for level in 0..self.indexer.levels() { - for i in 0..blooms.len() { - let bloom_index = self.indexer.bloom_index(block_number + i, level); - let is_new_bloom = match result.get_mut(&bloom_index) { - - // it was already modified - Some(to_shift) => { - *to_shift = &blooms[i] | to_shift; - false - } - None => true, - }; - - // it hasn't been modified yet - if is_new_bloom { - let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { - Some(ref old_bloom) => old_bloom | &blooms[i], - None => blooms[i].clone(), - }; - result.insert(bloom_index, new_bloom); - } - } - } - - result - } - - /// Resets bloom at level 0 and forces rebuild on higher levels. - pub fn reset_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap { - let mut result: HashMap = HashMap::new(); - - let mut reset_index = self.indexer.bloom_index(block_number, 0); - result.insert(reset_index.clone(), bloom.clone()); - - for level in 1..self.indexer.levels() { - let index = self.indexer.bloom_index(block_number, level); - // get all bloom indexes that were used to construct this bloom - let lower_indexes = self.indexer.lower_level_bloom_indexes(&index); - let new_bloom = lower_indexes.into_iter() - // skip reseted one - .filter(|li| li != &reset_index) - // get blooms for these indexes - .map(|li| self.data_source.bloom_at_index(&li)) - // filter existing ones - .filter_map(|b| b) - // BitOr all of them - .fold(H2048::new(), |acc, bloom| acc | bloom); - - reset_index = index.clone(); - result.insert(index, &new_bloom | bloom); - } - - result - } - /// Resets blooms at level 0 and forces rebuild on higher levels. pub fn reset_chain_head(&self, blooms: &[H2048], block_number: usize, old_highest_block: usize) -> HashMap { let mut result: HashMap = HashMap::new(); @@ -233,25 +175,6 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource result } - /// Sets lowest level bloom to 0 and forces rebuild on higher levels. - pub fn clear_bloom(&self, block_number: usize) -> HashMap { - self.reset_bloom(&H2048::new(), block_number) - } - - /// Returns numbers of blocks that may contain Address. - pub fn blocks_with_address(&self, address: &Address, from_block: usize, to_block: usize) -> Vec { - let mut bloom = H2048::new(); - bloom.shift_bloomed(&address.sha3()); - self.blocks_with_bloom(&bloom, from_block, to_block) - } - - /// Returns numbers of blocks that may contain Topic. - pub fn blocks_with_topic(&self, topic: &H256, from_block: usize, to_block: usize) -> Vec { - let mut bloom = H2048::new(); - bloom.shift_bloomed(&topic.sha3()); - self.blocks_with_bloom(&bloom, from_block, to_block) - } - /// Returns numbers of blocks that may log bloom. pub fn blocks_with_bloom(&self, bloom: &H2048, from_block: usize, to_block: usize) -> Vec { let mut result = vec![]; diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs index 2c1f6e298..b511365cf 100644 --- a/ethcore/src/chainfilter/tests.rs +++ b/ethcore/src/chainfilter/tests.rs @@ -47,6 +47,12 @@ impl FilterDataSource for MemoryCache { } } +fn topic_to_bloom(topic: &H256) -> H2048 { + let mut bloom = H2048::new(); + bloom.shift_bloomed(&topic.sha3()); + bloom +} + #[test] fn test_topic_basic_search() { let index_size = 16; @@ -58,9 +64,7 @@ fn test_topic_basic_search() { let modified_blooms = { let filter = ChainFilter::new(&cache, index_size, bloom_levels); let block_number = 23; - let mut bloom = H2048::new(); - bloom.shift_bloomed(&topic.sha3()); - filter.add_bloom(&bloom, block_number) + filter.add_bloom(&topic_to_bloom(&topic), block_number) }; // number of modified blooms should always be equal number of levels @@ -69,27 +73,27 @@ fn test_topic_basic_search() { { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 0, 100); + let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 0, 100); assert_eq!(blocks.len(), 1); assert_eq!(blocks[0], 23); } { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 0, 23); + let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 0, 23); assert_eq!(blocks.len(), 0); } { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 23, 24); + let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 23, 24); assert_eq!(blocks.len(), 1); assert_eq!(blocks[0], 23); } { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 24, 100); + let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 24, 100); assert_eq!(blocks.len(), 0); } } diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index 0b234b00d..548150f09 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -303,7 +303,7 @@ mod tests { self.numbers.get(&index).cloned() } - fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec { unimplemented!() } } From 4d40991c1a33effbc0b13fd2a0f71b6406118ff3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 16:01:45 +0100 Subject: [PATCH 024/753] Discovery test --- util/src/network/discovery.rs | 60 +++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index c580c8507..da8ce9e34 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -368,7 +368,7 @@ impl Discovery { // TODO: validate pong packet let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(0)))); let timestamp: u64 = try!(rlp.val_at(2)); - if timestamp > time::get_time().sec as u64 { + if timestamp < time::get_time().sec as u64 { return Err(NetworkError::Expired); } let mut entry = NodeEntry { id: node.clone(), endpoint: dest }; @@ -386,7 +386,7 @@ impl Discovery { trace!(target: "discovery", "Got FindNode from {:?}", &from); let target: NodeId = try!(rlp.val_at(0)); let timestamp: u64 = try!(rlp.val_at(1)); - if timestamp > time::get_time().sec as u64 { + if timestamp < time::get_time().sec as u64 { return Err(NetworkError::Expired); } @@ -395,8 +395,8 @@ impl Discovery { if nearest.is_empty() { return Ok(None); } - let mut rlp = RlpStream::new_list(cmp::min(limit, nearest.len())); - rlp.begin_list(1); + let mut rlp = RlpStream::new_list(1); + rlp.begin_list(cmp::min(limit, nearest.len())); for n in 0 .. nearest.len() { rlp.begin_list(4); nearest[n].endpoint.to_rlp(&mut rlp); @@ -404,8 +404,8 @@ impl Discovery { if (n + 1) % limit == 0 || n == nearest.len() - 1 { self.send_packet(PACKET_NEIGHBOURS, &from, &rlp.drain()); trace!(target: "discovery", "Sent {} Neighbours to {:?}", n, &from); - rlp = RlpStream::new_list(cmp::min(limit, nearest.len() - n)); - rlp.begin_list(1); + rlp = RlpStream::new_list(1); + rlp.begin_list(cmp::min(limit, nearest.len() - n)); } } Ok(None) @@ -422,6 +422,9 @@ impl Discovery { continue; } let node_id: NodeId = try!(r.val_at(3)); + if node_id == self.id { + continue; + } let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint }; added.insert(node_id, entry.clone()); self.ping(&entry.endpoint); @@ -476,3 +479,48 @@ impl Discovery { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use hash::*; + use std::net::*; + use network::node_table::*; + use crypto::KeyPair; + use std::str::FromStr; + + #[test] + fn discovery() { + let key1 = KeyPair::create().unwrap(); + let key2 = KeyPair::create().unwrap(); + let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 }; + let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 }; + let mut discovery1 = Discovery::new(&key1, ep1.clone(), 0); + let mut discovery2 = Discovery::new(&key2, ep2.clone(), 0); + + let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); + let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap(); + discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1. endpoint.clone() }); + discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2. endpoint.clone() }); + + discovery2.add_node(NodeEntry { id: key1.public().clone(), endpoint: ep1.clone() }); + discovery2.refresh(); + + for _ in 0 .. 10 { + while !discovery1.send_queue.is_empty() { + let datagramm = discovery1.send_queue.pop_front().unwrap(); + if datagramm.address == ep2.address { + discovery2.on_packet(&datagramm.payload, ep1.address.clone()).ok(); + } + } + while !discovery2.send_queue.is_empty() { + let datagramm = discovery2.send_queue.pop_front().unwrap(); + if datagramm.address == ep1.address { + discovery1.on_packet(&datagramm.payload, ep2.address.clone()).ok(); + } + } + discovery2.round(); + } + assert_eq!(Discovery::nearest_node_entries(&NodeId::new(), &discovery2.node_buckets).len(), 3) + } +} From a9e387523028421af0ec1b39212caeb16d2cd394 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 17:47:01 +0100 Subject: [PATCH 025/753] fixed ethsync tests --- sync/src/tests/helpers.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index c561b65a3..c4673e8e3 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -111,6 +111,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { + unimplemented!(); + } + fn block_header(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) } From 0e1e80477a0efd49fac14a7e4ddfa6f86b216c8c Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 18:36:34 +0100 Subject: [PATCH 026/753] Save key to a file --- parity/main.rs | 4 +++ util/src/network/host.rs | 63 +++++++++++++++++++++++++++++++++- util/src/network/node_table.rs | 2 +- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 460922b64..903b471c5 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -36,6 +36,7 @@ extern crate ethcore_rpc as rpc; use std::net::{SocketAddr}; use std::env; +use std::path::PathBuf; use rlog::{LogLevelFilter}; use env_logger::LogBuilder; use ctrlc::CtrlC; @@ -207,6 +208,9 @@ fn main() { net_settings.listen_address = listen; net_settings.public_address = public; net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); + let mut net_path = PathBuf::from(&conf.path()); + net_path.push("network"); + net_settings.config_path = Some(net_path.to_str().unwrap().to_owned()); // Build client let mut service = ClientService::start(spec, net_settings, &Path::new(&conf.path())).unwrap(); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 7366e129b..fb3bcee62 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -21,6 +21,9 @@ use std::str::{FromStr}; use std::sync::*; use std::ops::*; use std::cmp::min; +use std::path::{Path, PathBuf}; +use std::io::{Read, Write}; +use std::fs; use mio::*; use mio::tcp::*; use target_info::Target; @@ -340,7 +343,19 @@ impl Host where Message: Send + Sync + Clone { let addr = config.listen_address; // Setup the server socket let tcp_listener = TcpListener::bind(&addr).unwrap(); - let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() }; + let keys = if let Some(ref secret) = config.use_secret { + KeyPair::from_secret(secret.clone()).unwrap() + } else { + config.config_path.clone().and_then(|ref p| load_key(&Path::new(&p))) + .map_or_else(|| { + let key = KeyPair::create().unwrap(); + if let Some(path) = config.config_path.clone() { + save_key(&Path::new(&path), &key.secret()); + } + key + }, + |s| KeyPair::from_secret(s).expect("Error creating node secret key")) + }; let endpoint = NodeEndpoint { address: addr.clone(), udp_port: addr.port() }; let discovery = Discovery::new(&keys, endpoint, DISCOVERY); let path = config.config_path.clone(); @@ -914,3 +929,49 @@ impl IoHandler> for Host where Messa } } } + +fn save_key(path: &Path, key: &Secret) { + let mut path_buf = PathBuf::from(path); + if let Err(e) = fs::create_dir_all(path_buf.as_path()) { + warn!("Error creating key directory: {:?}", e); + return; + }; + path_buf.push("key"); + let mut file = match fs::File::create(path_buf.as_path()) { + Ok(file) => file, + Err(e) => { + warn!("Error creating key file: {:?}", e); + return; + } + }; + if let Err(e) = file.write(&key.hex().into_bytes()) { + warn!("Error writing key file: {:?}", e); + } +} + +fn load_key(path: &Path) -> Option { + let mut path_buf = PathBuf::from(path); + path_buf.push("key"); + let mut file = match fs::File::open(path_buf.as_path()) { + Ok(file) => file, + Err(e) => { + debug!("Error opening key file: {:?}", e); + return None; + } + }; + let mut buf = String::new(); + match file.read_to_string(&mut buf) { + Ok(_) => {}, + Err(e) => { + warn!("Error reading key file: {:?}", e); + return None; + } + } + match Secret::from_str(&buf) { + Ok(key) => Some(key), + Err(e) => { + warn!("Error parsing key file: {:?}", e); + None + } + } +} diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index 2b02748b4..e5c47cafb 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -273,7 +273,7 @@ impl NodeTable { let mut file = match fs::File::open(path_buf.as_path()) { Ok(file) => file, Err(e) => { - warn!("Error opening node table file: {:?}", e); + debug!("Error opening node table file: {:?}", e); return nodes; } }; From 4b9c7f7517eb79e95d7c9326cca734508614b1e0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 19:54:27 +0100 Subject: [PATCH 027/753] Add incoming connection to node table --- util/src/network/connection.rs | 11 +++++++++++ util/src/network/host.rs | 9 +++++++++ util/src/network/node_table.rs | 5 ++++- util/src/network/session.rs | 7 +++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 242e8935e..9e9304ca6 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -16,6 +16,7 @@ use std::sync::Arc; use std::collections::VecDeque; +use std::net::SocketAddr; use mio::{Handler, Token, EventSet, EventLoop, PollOpt, TryRead, TryWrite}; use mio::tcp::*; use hash::*; @@ -169,6 +170,11 @@ impl Connection { self.token = token; } + /// Get remote peer address + pub fn remote_addr(&self) -> io::Result { + self.socket.peer_addr() + } + /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "net", "connection register; token={:?}", reg); @@ -253,6 +259,11 @@ impl EncryptedConnection { self.connection.set_token(token); } + /// Get remote peer address + pub fn remote_addr(&self) -> io::Result { + self.connection.remote_addr() + } + /// Create an encrypted connection out of the handshake. Consumes a handshake object. pub fn new(mut handshake: Handshake) -> Result { let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public)); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index fb3bcee62..5f0bf19b9 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -663,6 +663,7 @@ impl Host where Message: Send + Sync + Clone { } } let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap(); + let originated = h.originated; let mut session = match Session::new(h, &self.info.read().unwrap()) { Ok(s) => s, Err(e) => { @@ -674,6 +675,14 @@ impl Host where Message: Send + Sync + Clone { session.set_token(session_token); io.update_registration(session_token).expect("Error updating session registration"); self.stats.inc_sessions(); + if !originated { + // Add it no node table + if let Ok(address) = session.remote_addr() { + let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; + self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); + self.discovery.lock().unwrap().add_node(entry); + } + } Arc::new(Mutex::new(session)) }); if result.is_none() { diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index e5c47cafb..40cc14743 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -200,7 +200,10 @@ impl NodeTable { } /// Add a node to table - pub fn add_node(&mut self, node: Node) { + pub fn add_node(&mut self, mut node: Node) { + // preserve failure counter + let failures = self.nodes.get(&node.id).map_or(0, |n| n.failures); + node.failures = failures; self.nodes.insert(node.id.clone(), node); } diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 5cda00567..f08fef385 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::net::SocketAddr; +use std::io; use mio::*; use hash::*; use rlp::*; @@ -144,6 +146,11 @@ impl Session { self.connection.set_token(token); } + /// Get remote peer address + pub fn remote_addr(&self) -> io::Result { + self.connection.remote_addr() + } + /// Readable IO handler. Returns packet data if available. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result where Message: Send + Sync + Clone { match try!(self.connection.readable(io)) { From 01a83e603140e82faf9586c4c824fececa69a791 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 20:28:27 +0100 Subject: [PATCH 028/753] Populate discovery from node table --- util/src/network/discovery.rs | 10 +++++++++- util/src/network/host.rs | 1 + util/src/network/node_table.rs | 8 +++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index da8ce9e34..08f5e5cf1 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -110,12 +110,20 @@ impl Discovery { } } - pub fn add_node(&mut self, e: NodeEntry) { + /// Add a new node to discovery table. Pings the node. + pub fn add_node(&mut self, e: NodeEntry) { let endpoint = e.endpoint.clone(); self.update_node(e); self.ping(&endpoint); } + /// Add a list of known nodes to the table. + pub fn init_node_list(&mut self, mut nodes: Vec) { + for n in nodes.drain(..) { + self.update_node(n); + } + } + fn update_node(&mut self, e: NodeEntry) { trace!(target: "discovery", "Inserting {:?}", &e); let ping = { diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 5f0bf19b9..c548d07cf 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -386,6 +386,7 @@ impl Host where Message: Send + Sync + Clone { for n in boot_nodes { host.add_node(&n); } + host.discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries()); host } diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index 40cc14743..9bce2d334 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -29,7 +29,7 @@ use hash::*; use rlp::*; use time::Tm; use error::*; -use network::discovery::TableUpdates; +use network::discovery::{TableUpdates, NodeEntry}; pub use rustc_serialize::json::Json; /// Node public key @@ -214,6 +214,12 @@ impl NodeTable { refs.iter().map(|n| n.id.clone()).collect() } + /// Unordered list of all entries + pub fn unordered_entries(&self) -> Vec { + // preserve failure counter + self.nodes.values().map(|n| NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }).collect() + } + /// Get particular node pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> { self.nodes.get_mut(id) From 0bef355494754507efc546bf80dc5634367c546e Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 20:34:05 +0100 Subject: [PATCH 029/753] Removed temp test code --- util/src/network/node_table.rs | 42 ++++------------------------------ 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index 9bce2d334..69d12dc87 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -330,6 +330,7 @@ mod tests { use std::str::FromStr; use std::net::*; use hash::*; + use tests::helpers::*; #[test] fn endpoint_parse() { @@ -380,57 +381,22 @@ mod tests { assert_eq!(r[2][..], id1[..]); } - use std::path::PathBuf; - use std::env; - use std::fs::{remove_dir_all}; - // TODO: use common impl - pub struct RandomTempPath { - path: PathBuf - } - - impl RandomTempPath { - pub fn new() -> RandomTempPath { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - RandomTempPath { - path: dir.clone() - } - } - - pub fn as_path(&self) -> &PathBuf { - &self.path - } - - pub fn as_str(&self) -> &str { - self.path.to_str().unwrap() - } - } - - impl Drop for RandomTempPath { - fn drop(&mut self) { - if let Err(e) = remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); - } - } - } - - #[test] fn table_save_load() { - let temp_path = RandomTempPath::new(); + let temp_path = RandomTempPath::create_dir(); let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); { - let mut table = NodeTable::new(Some(temp_path.as_str().to_owned())); + let mut table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned())); table.add_node(node1); table.add_node(node2); table.note_failure(&id2); } { - let table = NodeTable::new(Some(temp_path.as_str().to_owned())); + let table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned())); let r = table.nodes(); assert_eq!(r[0][..], id1[..]); assert_eq!(r[1][..], id2[..]); From 6d91852c5514b4dffaa84162340181b09736b405 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 21:32:09 +0100 Subject: [PATCH 030/753] test chainfilter on realdata --- ethcore/src/chainfilter/blooms.txt | 739 ++++++++++++++++++++ ethcore/src/chainfilter/logs.txt | 1013 ++++++++++++++++++++++++++++ ethcore/src/chainfilter/tests.rs | 99 ++- 3 files changed, 1844 insertions(+), 7 deletions(-) create mode 100644 ethcore/src/chainfilter/blooms.txt create mode 100644 ethcore/src/chainfilter/logs.txt diff --git a/ethcore/src/chainfilter/blooms.txt b/ethcore/src/chainfilter/blooms.txt new file mode 100644 index 000000000..204186ec3 --- /dev/null +++ b/ethcore/src/chainfilter/blooms.txt @@ -0,0 +1,739 @@ +300054 0x00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +300059 0x00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000 +300221 0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +301826 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +303166 0x00000000000000000000000000000000000000001000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000808000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000020000000001000000000000000000000000000000000000000000000000000000000000000000 +303345 0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +303379 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000800000000000000000000000000000000000002004000000000000 +303388 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000040000000001000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006001008000000000000008000080000000000000000000000000000000000000000001000000000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000800000000000000040000000000000000000002004000000000000 +303621 0x00000000000000000000008000000000200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000080000000000000000000000080000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000 +303670 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +303674 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +303683 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +303689 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +303692 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +303716 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +303717 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +303748 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +303756 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +303758 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +304090 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000 +304095 0x04000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000 +304107 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000400000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304113 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000003008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304222 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000800000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304245 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000080000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304247 0x000000080000000000000000000000800000020000000000000000000000000000000000000000000202000000000000008000004004000000000000000000000000000000000000000000000200000000200000000080000000000000000000000004000000000000000000000000000000001040000000000000000000000000000004000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000c0002000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304312 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000040000000000000200000000000000000000000000000000000000000000000000000000000000000000000000 +304319 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000100000000000020000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000080000000000000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000020000000000002000000000000000000040000000000000200000000000000000000000000000000000000000000000000000000000000000000000000 +304367 0x00000000000000000000001000000000000000000400020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000100000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304375 0x00000000004000000000001000000000000000000400020000000800000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000020000000000000000000000000000000000000000000000000008000000000000010000000008000000000000000000000000000000000008000800000000000000000000000100000000000000000000000000000000000000000100000000000000002000000000002000000040010010000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304407 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304431 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304433 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304608 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000400000000000000000000040000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 +304609 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000400000000000000000000040000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 +304788 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304794 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304819 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304835 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304849 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304856 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304862 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304872 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304881 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304902 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304996 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304999 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305006 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +305010 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305425 0x00000000004000000000000000000001000000000000020000000000000000000000000000000000000000000000000000000000008000000080000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010400000048000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000400000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305445 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000080000100000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305448 0x00000000004000000000000000000000000000000000020000000000000000000004000008000000000000000000000000000000000000000000000000000800000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000080000100000000002000000000000000000040000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +305450 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000080000000000000000000000000000020000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000004000000000000000000000000000 +305452 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000002000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000080000000000000000000000000000020000000000000000000000000000000000000000000008002000000000000000000040000000000000000000000000400000000000000000000000000000000004000000000000000000000000000 +305454 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000001000000040000000000000000000000000000000000000000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305457 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305463 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000200080000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305464 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000008000000000000000000000000000000000240000000200480000000000000000000000000000000000000000000000000000002000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305468 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305488 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000002000000000000008000000000000010000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305492 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000008000000000000000000000000000000008040000000000000000000000000000002000000000001000000000000000000000000000400000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000200000000000000000000000000000000000000000000 +305501 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000008000000000000000000040000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 +305502 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000008000000000000008000000000000000000040000000001000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000080000000000000000000000000000000000010000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 +305510 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000044000004000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305616 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305620 0x0000000000400000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000080000000000000000000000000000800000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000040000000001000000000a000000000000000010000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305622 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000080000000000000000000000000200000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 +305624 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000001000000000000000080000000000000000000000000200000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000004000000000000000000000000004000000000000000000000000000000000000080000000000000 +305626 0x00000000004000000000100000000000000000000000020000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000004000000000002000000000000002000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305627 0x00000001000000000000000000000200000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305629 0x00000001004000000000000000000200000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000040000000000000000001040000000000000000000000000000000000000000000000000000000000000000000 +305634 0x00000000005080000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008020000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000 +305826 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000400000000000000002000000000000000000840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305827 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000100000000000000000000000000040000000000000000000000000000000000000000000000000000000000000040000000000000000000000010000000008000000000000000000000000000000100008000000000000000000000000000000000000000000000000000000000000000000000400000000000000002004000000000000000840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305829 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000008000000000080000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305834 0x00000000004002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000041000000000000000000000000000000000000008000000000080000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000020000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305839 0x00000000000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000080000000000000000000000000000000000000000000000000000000000000 +305841 0x40000000004000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000008000000008000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000080000000000000000000000000000000000000000000008000000000000000 +306889 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +307290 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +307508 0x00000000000000000000000000000000000000000000020000000000000000000000200000000000400000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +307509 0x00000000004000000000000000000000000000000000020000000000000000000000200000000000400000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000040000000000000000000000000000000000000000000000000000000000000000000000000010000000008000010000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +307513 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000004000000000000000000000000010000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000200000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +307519 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000001000000000000002000000000000000000040000000000000000000000000000000000000000000080000000000000000000000000000000000000000000 +307528 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000020000000000000000000000000000000000000000000000000000000000000000100000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +308010 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000080000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000 +308115 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +308124 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +308127 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +308157 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 +308183 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000002020000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +308190 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 +308216 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000002020000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +308224 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 +308257 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308265 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308267 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308268 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308285 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308599 0x00000000000000000000000000000000000000000000080000000000000800000000000000000010000000000000000000200002000000000000000000000000000000000000000000020000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004010010000002000000000000000400000000000000000000000000000000000000000000040000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309175 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309177 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309184 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309186 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309190 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309194 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309198 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309417 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +309881 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 +309883 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 +309892 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 +310069 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310114 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310116 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310177 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310533 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310589 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310592 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310599 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310601 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310604 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311317 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311758 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +311858 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311859 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311865 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311888 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312096 0x00400000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000200000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312124 0x00400000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000200000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312367 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312371 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312383 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313355 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313368 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313507 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +313526 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313724 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313789 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +314190 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +314375 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000008000400000000000000000000000000 +315698 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +315705 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +315780 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +316726 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +316747 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317179 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +317522 0x04000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006001008000000000000008000080000000000000000000000000000000000000000001000000000100000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000040000000000000008000002004000000000000 +317526 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317536 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000020000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000800400000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +317567 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001004000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317597 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +317606 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +317610 0x00000000000000200000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000800000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000001044000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000400000000000000000000000000000000000000000000000000000000000000000000440000000000000000 +317643 0x00000000000000200000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000010000000000000000000000000000004000000000020000000000000000000000000000000000000000000001004000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317646 0x00000000000000000000000000000000000000000000000000004000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000010000000000000000000000000000004000000000020000000000000000000000000000000000000000000001000000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317660 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000000400002000000000000000000000000000000000000000000000000000008000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +317957 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +318030 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318032 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318033 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000800000000000000000000000000000000000002004000000000000 +318034 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318036 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318063 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000040000000001000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000040000000000000800000000000000000000000000000000000002004000000000000 +318074 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000100000010020000000000000000000200000000000000000080000000020000000000000000000800000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000000000000000000000000000000000000000102000000000000000 +318096 0x04000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000100000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000008000002004000000000000 +318137 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +318528 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000020000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000808400000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +318627 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400002000000000000000000000000000000000000000000000008000008000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +318639 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000800000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000002000000000000000000000010000000000000004800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000080000000000000000000000000 +318650 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000800000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000010000000000000004000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000 +318653 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000010000000000000000000000000800000000000000000000000000000000000000000000000000000 +318904 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +319523 0x00000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000400000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +321346 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +321884 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +321900 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +322038 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322041 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322043 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322047 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322048 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322056 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322059 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000001080000800000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +322083 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322090 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322108 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000010020000000000000000000200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000100000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000008000100000000000000000 +322121 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000010000000000100000010020000000000000000000200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000001080000800000000000000000000000000000000000004000000000000000000000000000000808000000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000100000000000000000 +322122 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000100000010020000000000000000040200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000040000000000000800000000000000000000000000000000000100000000000000000 +322128 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000010020000000000000000000200000000000000000088000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000008000002000000000000000000000000000000000000000000000008000008000000000000000000000000000000000800000000000000000000000000000000000100000000000000000 +322454 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008010000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000010000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000080000000000000000000000000000000000000000000000000000000000000000000000000 +322509 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008010000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000080000000000000000000000000000008000000000200000000000000000010000000000000000000000000000000000000000000000000000000002000000000200000000040000000000000080000000000000000000000000000000000000000000000000000000000000000000000000 +322550 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322749 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000400000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006400000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000080000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +322750 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000040000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322752 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000008000000000000000000080000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000080000020000000000000040000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000080000000000000000000000 +322758 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322760 0x00000004004000000000000000000000000000000000020000000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000008000000000000000000000000000000000040000000000002000000000000000000000000000000000000000000004000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322764 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000001000000000000000000000000000000000000000000000000000000000000001000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000020000000000000000000000000000000 +322765 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000001000000000000000000000000000000000000000000000000000000000000001000000000000000002000000000200000000040000000000000000000000000000000000000000000000000000000020000000000000000000000000000000 +322767 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080000000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 +322768 0x00000000004000000000000000000000000000000000120000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000400000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080004000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 +322774 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000008000000000000000000000000000000000000000000000000000000000000000000002001000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322776 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000010000000000000000000000000040000000000000000000000000000000010000000008000000000000000000000000000000000009000000000000000008000000000000000000000000000000000000000000000000000000000000000000002001000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322777 0x00000000004000000000008000100000000000000000020000000000000002000000000000000000000000000000000000000004000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000020000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000001000000000000000000000000000000000000000000000000 +324029 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +324316 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000004000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +324318 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000 +324322 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000400000000000000000000000000000000000000000000000000000008000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +325807 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +326760 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 +327103 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +327105 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +327227 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +327399 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +327544 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +327690 0x00000000000000000000000000000100000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +328002 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000200000000000 +328269 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +328529 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +328585 0x20000000000000000000100000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +328870 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +329480 0x00000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000200000000000000000000000020000000000000000000000000000000000000000000 +329484 0x00000000004000000000000008000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000040000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000200000000000000000000000020000000000000000000000000000000000000000000 +329485 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329491 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329513 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329519 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329659 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000020000000000000000000000000000000000000000000000000000000000020000000010000000008000000000000000000000000000000000008000000400000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000020000000 +329667 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000100000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 +329668 0x0000000000400000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000004000000000000010000000000000000000000000000000000000000000000000001000000000000000000001000000000c000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000002000000000000000000800000000000000000000000 +329673 0x00000000004000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000004000000000000000000000000000000000000000000000000004000000000000000000010000000008000000000000000000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000400400000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +329740 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000010000000000000 +329749 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000008000000000000000000000000000000000000000002000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +329750 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000008000000000000000000000000000000000040000000040000000000000000000000010000000000000000000000000000000000000000000000000000010000000008000000000000000000000080000000000008000000000000000000000000000000000000000002000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000400000000000000000000000000000000000000000000 +329824 0x00000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000008000000008000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329964 0x00000000000000000000000000000000000000000000000000000000100000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +330023 0x00000000000000000000000000000000000000000000000000000000100000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +330207 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000004000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000 +330473 0x00000000000400000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000001000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +330511 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +330579 0x00000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000001000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +330683 0x00000000000000000000000000000000000000000000080000000000004000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +330919 0x00020000000000000000000000000000000000000000000000000000000000000008001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +331009 0x00000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +331542 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000100000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000004000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +332007 0x00000000000000000000000000000000000000000000000000000200000080000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +333256 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000400000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000010000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +333294 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +333583 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000200000000000000000000000000000000000000000000000000010008000000000000000 +333640 0x80000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000004000000008000000000000000000000000000000000000010000000000000000000000000000000000008000000000000000 +334263 0x00000000000000080000000000000000000000000000000000000000000000000100001000000000000010000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +334279 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000040000020000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000 +334883 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +334915 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000004000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +334919 0x00000020000000000000000000000000000000000000000000000000000000000000001000000000000020000000000000008000000000000000000000000000000000000020000000000000020000812000002000000000000000000000000001000000000000000000000000000000400000000000000000000000000000000000000000000000040000800000000010000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000008000400000000008000000000000000 +335076 0x00000000000000001000000000000000000000000000000000000000000000000000001000000000000000000100000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +335348 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000008000000000000000000000040000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000 +335643 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +335649 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +335652 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +335684 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000002000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000 +336089 0x0000000000000000000000000000000000000000000000000000000000020000000000100000000000000000000000000000800000000000000000000000000000000000000000000000000000000080200000a000000000000000000000000001000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +336231 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336234 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336242 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336243 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336244 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336245 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336247 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336248 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336255 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336260 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336263 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336264 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336266 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336334 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336336 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336337 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336338 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336439 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336451 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336452 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336453 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336461 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336495 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336497 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336507 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336508 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336509 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336510 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336518 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336520 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336521 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336522 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336526 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336527 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336528 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336543 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +337012 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000001000000000000000000000000400000000000000802000002000000200000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +337642 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000408000000000000000000000000000000000040000080000000000000000080000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000020000000000000000002000000000000000000040000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +337647 0x00000000000000000000000000000000000000000000020000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337649 0x00000000004000000000000000000000000000000000020000000000000080000000100000000000000000000000000000000000000000000000000000000000000000000000000000008002000000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000002000010000000008000000000000000000000000000000000008000000000000000000000000000000000200000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337653 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000040000000000000000000040000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337654 0x00000000004000000000008000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000020000040000000000000000000040000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337655 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000040000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000400000000040000000000000000000000000000000000000000000000000000000000000000000000 +337656 0x00000000004000000000000000000000000400000000020000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000008000040000000000000000000000000000040000000000000000000000000000000000000000000000000000004000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000400000000040000000000000000000000000000000000000000000000000000000000000000000000 +337663 0x00000000004000000000000000000000080000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000001000000000000000000000000000050000000000000000000000000040000000000000000000000000000000000000000004000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 +337664 0x00000000000000000000000000000000000000000000020000000010000000000000000000000000001000000000000000000000000000000000000000000000000200000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337669 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000008000000000 +337672 0x40000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000020000000000000010000000008000000000000000000000000008000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000008000008000000000 +337731 0x00000000000000000000000020000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000800000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +338275 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +338281 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +338336 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +338424 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008004000000000000000000000000000000000000100000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +338435 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000004000000000000000000000000010000000000000000000000000000000000000 +338439 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000010802000002000000000000000000000000001000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000 +338661 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +338991 0x00000000000000000000000000200000000000000008000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000400800000000000000000000000000000010000000000000000000000000000000000000000000000000 +339173 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002400000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +339369 0x00000020000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +339427 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000020000000000000000000001000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +340633 0x00000000000000000000000000000000000000000000020000000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340635 0x00000000004000000000000000000000000000000000020000000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000200000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000001000000000200000000000000000000000000000000000000000000000000000000000000000000 +340653 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000001000000002000000000000000000040000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 +340658 0x0000000000400000000000000000000400000000000002000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000001000000000800000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000100000000a000000000000000000040000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 +340674 0x00000000000800000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040080000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340675 0x00000000004800000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000040080000000000000000000000000000000000002000000000000000000080000000000000000000000000000 +340685 0x00000000000000000000000000000000000000000000020010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340686 0x00004000004000000000000000000000000000000000820010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000040000000000000000000000000000000000000000000000000002000000000000000000000000000000000000 +340700 0x00000000004000000000000000000000000000000000020001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000080000000000000000000000000000000000008000000000000000000000000000000000000000000002004200000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +340708 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 +340710 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000000000000000000000040000000000000100000000000000000800000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000400000000000000000000000000000000000000000000000000002000002000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 +340712 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000008000000000200000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340713 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000080840000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000028000000100000000000000000000000000008000000000200000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +340718 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000100000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000002000000000000 +340719 0x00000000004000000000000000000000000000000000020000000040000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000080000002000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000100000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000002000000000000 +340727 0x00000000004000000000040000002000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000200000000000080000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +340728 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000002000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000100000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340835 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +340988 0x00000000000000000010000000000000000000000010000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000008000000000000000 +341695 0x00000000000000000000000010000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000 +341985 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +341997 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104000000000004000000000000001000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +342001 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +342004 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +342007 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000004000000000000001000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +342008 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +342026 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000020000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342027 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342033 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342035 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342036 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342041 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342047 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000002000000104000000000044100000000000001000002000000000000000000000001000000000000000000004000000000000080000000000000000000000000000000000000002000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342053 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342080 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000000000000000000000000000000000000000040000000000000000000001040000000000000000000000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000440000000000000000 +342101 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342107 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342111 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342115 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342118 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342125 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342140 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342141 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342145 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000000000000000000000000000000000000000040000000000000000000001040000000000000000000000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000440000000000000000 +342162 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342173 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342188 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342272 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000400000000000000000 +342386 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000000000000001000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000004000000000000000000000000010000000000000000000400000000000000000 +342399 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000 +342466 0x00000000000000000000000000000000000000000000000000002000000000000000001000000000080000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +342601 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342616 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342618 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342924 0x00000000000000000000000000000000000010000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +342964 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +343006 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000080000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000 +343021 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000004000000000000000000000000000000000000000000000000080000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000 +343059 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000008000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +343079 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000200000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +343083 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000040000000000000802000002000000000000000000000000001000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +343133 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +343162 0x00000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000100000000000000000000000000008000400000000000000000000000000 +343185 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000008000400000000000000000000000000 +343339 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000080000000000000000802000002000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +343946 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +343966 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +343971 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +344121 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 +344164 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 +344839 0x00000000000000000000000000000000000000000000000000000000000000000200001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000008000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +345506 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +346112 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346392 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346395 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346398 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346425 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346448 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346451 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346454 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346464 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346466 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +347014 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +347301 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 +347333 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 +347613 0x00000000000000000000000000000000000000000800000000000000000000000000000000000000000001000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000000002000000000000000000000000000000000000000000000000000000001000000040000000000000000000000800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001000000000000000000000 +347700 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400010000000000000 +347705 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400010000000000000 +347711 0x00000000000000000000000000000000000000004000000000020000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 +347853 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 +347953 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 +347958 0x00000000000000000000000000000000000000004000000000020000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 +347960 0x00000000000000000000000000000000000000000000000000020000002000000001000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 +348019 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +348244 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000004000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +348443 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000400000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +348675 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000080000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000400100000000000000000000000000000000000000000000000008000000000000000 +348743 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +348936 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000100000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000002000000000000000000000000000000000000000008000000000000000 +350544 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +351473 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 +353157 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +353181 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000400000000000000000 +353196 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +353273 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000 +353276 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +353359 0x00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000200000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000040 +353360 0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000040 +353361 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008002400000000000000000000000000 +353367 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000080000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000008000000000000000 +353370 0x02000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +353438 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000080000000000000000000000000000000000000000000000000002000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000040 +353443 0x0000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000a000400000000000000000000000000 +353447 0x00000028000000000000000000000080000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +353479 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000002000001000000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +354071 0x02000000000000000000000000000000000000000000020000000000000000000000000040000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000020000000000000000000000200000000000000020000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000 +354151 0x00000000000000000000000000000000000000000000002000000000000000000000400000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004040000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000080000000400000000000000000000000000000000000000000000000000000000000000000000000000000 +354162 0x00000000000000000000000000004000000000000000000000000000000000000000410000000000200000000000000002000000000002000000000040000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000 +354233 0x00000000000000000000000000000000000000000000000000000000000000000000400040000004000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024040000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000400000000000000000000000040000000000000000000000000000000000100000000000000000 +354585 0x00000000000000000000000000000000000000000000000000100000000000000000400000000000200000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004001000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000 +354866 0x00000000000000000000000000000000000000000000000000001000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001 +356461 0x00000000000000000000000000200000000000000000000000000000010000000000000000000000000000000000000000202000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +356488 0x00000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000200000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000020000000000000080000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000 +356513 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000080000000000000a00000000000000000000000 +356526 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +356535 0x00000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000 +356543 0x00000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000800080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000 +357195 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +357579 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357590 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000200000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +357592 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357600 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357622 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357630 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +358290 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +358426 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +358556 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +358811 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000400000000000000000000000000000000002000000000008000000000000000 +359114 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +359375 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000100000000000000000 +359378 0x00000020000000000010000000000000000004000000000000000200400000000000000000000000000000000002000000000000000000020000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000040010000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000400000000000 +359538 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +361585 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +361588 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +361732 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000842000002000000000000000000000000001000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000080000000000000000000000000000000000000000000000000000008000000000000000 +361757 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +361775 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +362002 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000010000000000000000000000000802000002000000000000000000000400001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +365791 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 +365793 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000400010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +369141 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000200000000000000000000000000000000000000000000000000000000000000000008000000000010000 +369239 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369249 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369253 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369259 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369261 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369263 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369274 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369426 0x00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000200000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000040 +369428 0x20000020000000000000000000800000000004000000000000000200400000000000000040000000000000000000000000000000000000020000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000000010000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000008000400800000000000000000000000 +369431 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000400000000000100000000000040 +369538 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 +369540 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000008000400000000000000000000000000 +370399 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000001000000000000802000002000000000000000000000000001000000100000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +370517 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +370545 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371190 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371280 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371286 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371288 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371299 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371307 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371327 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371329 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371352 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371360 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371362 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371369 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371378 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371450 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371489 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371509 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371532 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371658 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371660 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371876 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371904 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371906 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371912 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371914 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371918 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371931 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371933 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371938 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371940 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371973 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +372006 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +372014 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +372847 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374209 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374225 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374365 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374388 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001000000000000000000000200000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +375079 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +375093 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +375401 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +375440 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +375447 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376493 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376573 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376644 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376650 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376668 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +376906 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377026 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +377139 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377506 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377523 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +377525 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377581 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 +377586 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000040000000000000000000000100000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +377608 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377627 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377629 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377703 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377730 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +377746 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000400000000000000000 +377877 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +377894 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +377905 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +377917 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +377922 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +377925 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +378345 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +378347 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +379027 0x00000020000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +379032 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +379039 0x08000020000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +379158 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000400000000000000000002000040000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379161 0x00000400004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000008000000000000000000000000000000020008000000000000000000000000000000000000000000000000000000000000000000400000000000000000002000040000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379163 0x00000000000000000000000000000000000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000080000000000000000000000000000000000000000 +379164 0x00000000004000000000000000000000000000100000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000100000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000080000000000000000000000000000000000000000 +379167 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000004 +379170 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +379171 0x00000000004000000000000000800000000000000000020000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000008000000000000000000000000000002000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000004 +379172 0x00000000000000000010000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000200000000000000000000000000000000000000000000000000000000000000000000000 +379176 0x00000000004000000010000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000100000000000000000000000000000000000000000200000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000040000000000000000000000000000000002000000000000000000040000000000000000200000000000000000000000000000000000001000000000000000000000000000000000 +379180 0x00000000000080000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000800000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379182 0x00000000004080000000000002000000000000000800020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000800000000000000000000050000000008000000000000000000000000800000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379210 0x00000000000000040000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000004000000000000000000000400000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379212 0x00000000004000040000000000000000000000000000020000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000200000000000008000000000000000000000000000000000000000004000000000000000000000400000000000000000000002000000000000000000040002000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379214 0x00000001000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379216 0x00000001004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000008000000000000008000000000000000000000000000000000040000000000000000000000000000000000020000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000020002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379217 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000800000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 +379219 0x00000000004000000000000000000000000000000000020000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000008000000000000000000000000010000000000000000010000000008800000000000000000000000000000000008000020000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 +379220 0x00000000000000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000100000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379224 0x00000000004000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000008000000000000000040000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000100000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000400000000000000 +379235 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000080000000000000000000000000000000000000000800000000000000000000000000000 +379237 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000100000000008000000000000000000000000000000000000010000000008008000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000080000000000000040000000000000000080000000000000000000000000000000000000000800000000000000000000000000000 +381271 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +381276 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +381689 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +382200 0x00000020000000000000000008000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +382217 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000400000010000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +382644 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 +383284 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383337 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383354 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383361 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383427 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +383466 0x00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383469 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000001000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383515 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +383519 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +383630 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000400000000000000000 +383760 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383802 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000080000000000400000000000000000 +383815 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000000000000010000000000000000000000040000000000000000000000000000000020000000100000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383844 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383852 0x00000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000002000000000000000000000000000400000000000000004000000000000000080000000000000000000000000000000000000001000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383859 0x00000000000000000000000000000000000000804000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000002000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +383864 0x00000000000000000000000000000000000000800000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000080000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +383968 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +383973 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +384127 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +384138 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384149 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384173 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000400000000000000000000080000000000000000000000000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000800000000000000000000000000000400000000000000000 +384301 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000040000000000000000000000000000000000000000400000000000000000 +384422 0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384506 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +384511 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +384546 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +384771 0x00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000800000 +384825 0x00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000 +384861 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000100000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384917 0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384923 0x00002000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000001000000 +384965 0x00000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +385067 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000000 +385073 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000000 +385356 0x00002000000000000000000000000000000000010000000000000000000000000000000400000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000001000000 +386571 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +386620 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 +386736 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000010 +386786 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000280000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000040000000000000000000000000000000000000000000000000000000000000000010 +386795 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000008000000000000000000010 +386804 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000040000000000400000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386812 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000040000000000000000008000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386818 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000800000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386899 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000080000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386939 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000000000000000000000000000000000200000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000 +386945 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000020000000000000000000800000000000000000000000000000000000000000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +386975 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000100000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +387011 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000010000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +387014 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000 +387016 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000400000000800000000 +387032 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000 +387044 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000020000000000000000000000000000000000000000000080000000000000000000000 +387045 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000400000000800000000 +387206 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387225 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387241 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387276 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000008000000000000000004000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000021000000000000000000004000000000000000000000400000000000000000000000000000000080000000000000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387284 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +387365 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000 +387615 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387627 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000800000000000000000400000000000000000 +387641 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +387648 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387654 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387658 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387683 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387688 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387690 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387761 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +388108 0x00000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388111 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000800000000 +388150 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000800000000 +388246 0x00000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000 +388285 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388296 0x00000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000 +388516 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388860 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +388893 0x00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000020000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388894 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +388907 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000104000000000004000000000000001000000000000000000000000000001000000000000000000004080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000004000000000000000400000000000000000 +388909 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000400000000000000000 +388912 0x00000000000000000000000000000000000000004000000000020000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000004000000000000000040000000000000000 +388918 0x00000000000000000000000000000000000000000000000000020000002000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000004000000000000000040000000000000000 +388923 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000004000000000000000400000000000000000 +388940 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +388971 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000004000000000000000000000000000000000000000800000000000000000000000000000000000 +388990 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 +389012 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 +389158 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 +389206 0x00000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000400000000000000000 +389238 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +389277 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000400000000000000000 +389292 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +389301 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +389309 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +389324 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000800000024000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000 +389328 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +389343 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +390001 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000001000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390004 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000200000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +390024 0x00000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390042 0x00000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390236 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390306 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000001000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390867 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +391685 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +391690 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +391691 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +391697 0x00000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000040000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000 +391713 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 +391849 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000400000000000000000 +392002 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000 +392097 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392104 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392110 0x00000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000 +392294 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000 +392697 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 +392960 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392970 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392990 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +393302 0x00000010000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000400000000000000000 +393370 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +393752 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +394354 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000800000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394389 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394390 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394391 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394393 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394394 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394395 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394426 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000200000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394800 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000100000010000000000000000000000000000000000000000000000000000000000020000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +395595 0x00000000000000000000000000000000000000000000000000000000000100000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000800000000000000000000000000000000000000000000000000000000000000000008000000000000000 +395969 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +396348 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 +397108 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 +397588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 +397591 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 +398412 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +398456 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +398477 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +398679 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +398968 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020200000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000 +398972 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000400000000000000000 +399058 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +399804 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 +399849 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/ethcore/src/chainfilter/logs.txt b/ethcore/src/chainfilter/logs.txt new file mode 100644 index 000000000..2127af242 --- /dev/null +++ b/ethcore/src/chainfilter/logs.txt @@ -0,0 +1,1013 @@ +300054 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d617274696e0000000000000000000000000000000000000000000000000000 +300059 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000059 +300221 0xef2d6d194084c2de36e0dabfce45d046b37d1106 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +301826 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303166 0xef2d6d194084c2de36e0dabfce45d046b37d1106 0x6c692d39f4045f32ff9259df5b527f0ebf04abdbbb44231574a0e5398ff21fae 0x0000000000000000000000000000000000000000000000000000000000000738 +303345 0xef2d6d194084c2de36e0dabfce45d046b37d1106 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +303379 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000000 +303379 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000000 +303388 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000abad6ec946eff02b22e4050b3209da87380b3cbd 0x0000000000000000000000000000000000000000000000000000000000000001 +303388 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000001 +303621 0x584aeb8bcb61e5c1a84d167c2511abf581713495 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 0x00000000000000000000000071353366b3ca768968ea084167655e1cc09938f2 0x000000000000000000000000302f330f8fb5f122b388acb8d85ccb0e712bb5ff +303670 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303674 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +303683 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303689 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303689 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +303692 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303692 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +303716 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +303717 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +303748 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303756 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303756 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +303758 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303758 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +304090 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000001 +304095 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000002 +304107 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000003 +304113 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000004 +304222 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000005 +304245 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000006 +304247 0x4d498b18abcf83a15d3364d7419a4ef382982c7d 0x7d596234f9de8bba372a6b76656b35620eb6a5211bb764a81b1891567aed662a 0x0000000000000000000000000000000000000000000000000000000000000067 +304247 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0xe1a3670bcee4a697f1f4341b87487549f80e87998434bb9c2c08c73966d0766d 0x0000000000000000000000000000000000000000000000000000000000000006 0x0000000000000000000000000000000000000000000000000000000000000067 0x0000000000000000000000004d498b18abcf83a15d3364d7419a4ef382982c7d +304312 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506c616e657468657265756d0000000000000000000000000000000000000000 +304319 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x506c616e657468657265756d0000000000000000000000000000000000000000 0x0000000000000000000000008394a052eb6c32fb9defcaabc12fcbd8fea0b8a8 +304319 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506c616e657468657265756d0000000000000000000000000000000000000000 +304367 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7261626269740000000000000000000000000000000000000000000000000000 +304375 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304375 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x7261626269740000000000000000000000000000000000000000000000000000 0x000000000000000000000000f50466e3f27955334fff159e9d6e325c11eb85d6 +304375 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7261626269740000000000000000000000000000000000000000000000000000 +304407 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304431 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304433 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304608 0x7d00703c96bcd2b2af420cf165241396528b5e99 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +304609 0x7d00703c96bcd2b2af420cf165241396528b5e99 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +304788 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304794 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304819 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304835 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304849 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304856 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304862 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304872 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304881 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304902 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304996 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304999 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +305006 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +305010 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +305425 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x427573696e657373000000000000000000000000000000000000000000000000 +305425 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x427573696e657373000000000000000000000000000000000000000000000000 0x000000000000000000000000b48dafc23dc5f232f2e7a35a2d2bb1b4ab02c48a +305425 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x427573696e657373000000000000000000000000000000000000000000000000 +305445 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4574686572000000000000000000000000000000000000000000000000000000 +305448 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4574686572000000000000000000000000000000000000000000000000000000 0x000000000000000000000000b56aea97a14a10f536fa4f770b900e12231a018e +305448 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4574686572000000000000000000000000000000000000000000000000000000 +305450 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x46756e64696e6700000000000000000000000000000000000000000000000000 +305452 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x46756e64696e6700000000000000000000000000000000000000000000000000 0x000000000000000000000000ace8a25b438c0d8c16cf578ddeb015fd1f714896 +305452 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x46756e64696e6700000000000000000000000000000000000000000000000000 +305454 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x436f696e00000000000000000000000000000000000000000000000000000000 +305457 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7266696b6b690000000000000000000000000000000000000000000000000000 +305463 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461690000000000000000000000000000000000000000000000000000000000 +305464 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6461690000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000968ea5eed1d40486a7f87991c3299d383a8e85d2 +305464 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461690000000000000000000000000000000000000000000000000000000000 +305468 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x77656966756e6400000000000000000000000000000000000000000000000000 +305488 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5265776172647300000000000000000000000000000000000000000000000000 +305492 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5553440000000000000000000000000000000000000000000000000000000000 +305492 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x5553440000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000b52f670a662fc87e9a976f50f7ed7c056b369684 +305492 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5553440000000000000000000000000000000000000000000000000000000000 +305501 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x496e737572616e63650000000000000000000000000000000000000000000000 +305502 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x496e737572616e63650000000000000000000000000000000000000000000000 0x0000000000000000000000004db56c006f6d9e2edf742438c7a7dc032a5c3025 +305502 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x496e737572616e63650000000000000000000000000000000000000000000000 +305510 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5365780000000000000000000000000000000000000000000000000000000000 +305616 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616d706169676e000000000000000000000000000000000000000000000000 +305620 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x43616d706169676e000000000000000000000000000000000000000000000000 0x00000000000000000000000076ff1940d6c15ae2ef8436de7564485770356076 +305620 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616d706169676e000000000000000000000000000000000000000000000000 +305622 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4769667463617264000000000000000000000000000000000000000000000000 +305624 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4769667463617264000000000000000000000000000000000000000000000000 0x000000000000000000000000f8aaa4ccb80d0e047e9293619b47160e2c3b82d8 +305624 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4769667463617264000000000000000000000000000000000000000000000000 +305626 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4c6f616e73000000000000000000000000000000000000000000000000000000 +305626 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4c6f616e73000000000000000000000000000000000000000000000000000000 0x000000000000000000000000569a16c067a308a5ea90b15a7caeae8705500569 +305626 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4c6f616e73000000000000000000000000000000000000000000000000000000 +305627 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53686f7070696e67000000000000000000000000000000000000000000000000 +305629 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53686f7070696e67000000000000000000000000000000000000000000000000 0x00000000000000000000000068057d1adb313d52890691adf051df3000a3d57d +305629 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53686f7070696e67000000000000000000000000000000000000000000000000 +305634 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4164647265737300000000000000000000000000000000000000000000000000 +305634 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4164647265737300000000000000000000000000000000000000000000000000 0x000000000000000000000000ea5511d3653d36fb55b53948d23e55a23c4fead7 +305634 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4164647265737300000000000000000000000000000000000000000000000000 +305826 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f6e6579000000000000000000000000000000000000000000000000000000 +305827 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4d6f6e6579000000000000000000000000000000000000000000000000000000 0x000000000000000000000000ef15babca7a972f141556571e5b08e3175cf97b2 +305827 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f6e6579000000000000000000000000000000000000000000000000000000 +305829 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x436f75706f6e7300000000000000000000000000000000000000000000000000 +305834 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x436f75706f6e7300000000000000000000000000000000000000000000000000 0x000000000000000000000000a6cee167a6c4a531c6d16fdff7aa2de9f861cb07 +305834 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x436f75706f6e7300000000000000000000000000000000000000000000000000 +305839 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4163636f756e7400000000000000000000000000000000000000000000000000 +305841 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4163636f756e7400000000000000000000000000000000000000000000000000 0x0000000000000000000000000ec0d6547c59c38a9105525f0c10ec4d4a0b1afb +305841 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4163636f756e7400000000000000000000000000000000000000000000000000 +306889 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +307290 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +307508 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5858580000000000000000000000000000000000000000000000000000000000 +307509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x5858580000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000a61bfbbe1af5fde18193ffeffe9254b939d6de96 +307509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5858580000000000000000000000000000000000000000000000000000000000 +307513 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x537572696e616d65000000000000000000000000000000000000000000000000 +307519 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x546f797300000000000000000000000000000000000000000000000000000000 +307528 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5757570000000000000000000000000000000000000000000000000000000000 +308010 0x37c8f253d780913bc2b2d63c4f13f991a9ce7880 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +308115 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +308124 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308127 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +308157 0xd202f28e78e9802a95fe5b3d26785257fcf8493b 0xfb989cb0d132b51483b9258c1befbe92caa5f5b046af3dfdcc617dcf425af493 +308183 0x58db357c28947271c883b11bab4caaa445e0ebc0 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +308190 0xd202f28e78e9802a95fe5b3d26785257fcf8493b 0xfb989cb0d132b51483b9258c1befbe92caa5f5b046af3dfdcc617dcf425af493 +308216 0x59a964f830b3593af88b3d5b2835938d7985fbae 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +308224 0xd202f28e78e9802a95fe5b3d26785257fcf8493b 0xfb989cb0d132b51483b9258c1befbe92caa5f5b046af3dfdcc617dcf425af493 +308257 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308265 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308267 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308268 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308285 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308599 0xc699608dd050d140e37cd402efe8343abcce6cd3 0x9ce147531995c591b0b50012b20f7f6d0dea75281159a58b8637542388f14626 0x00000000000000000000000048175da4c20313bcb6b62d74937d3ff985885701 0x00000000000000000000000023b666fd0ef4778c7557c3e33b126c1f10211941 0xffffffffffffffffffffffffffffffffa0e7153557ae4b988c928492845e7919 +309175 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309177 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309184 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309186 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309190 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309194 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309198 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309417 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +309881 0x80603decb9f6326b05fec23c9a830d6cf506aa88 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +309883 0x80603decb9f6326b05fec23c9a830d6cf506aa88 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +309892 0x80603decb9f6326b05fec23c9a830d6cf506aa88 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310069 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +310114 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310116 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310177 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310177 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310177 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310533 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +310589 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310592 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310599 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310601 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310604 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311317 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311758 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +311858 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311859 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311865 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311888 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +312096 0xb7871c70fcba963f502f5b25ca39932820f23206 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312124 0xb7871c70fcba963f502f5b25ca39932820f23206 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312124 0xb7871c70fcba963f502f5b25ca39932820f23206 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312367 0x5e50225b8dccefd89dcbae96e73f71e59a4e2529 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312371 0x5e50225b8dccefd89dcbae96e73f71e59a4e2529 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312383 0x5e50225b8dccefd89dcbae96e73f71e59a4e2529 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +313355 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +313368 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +313507 0x8465dac1172b6abe303bead4d06125aed72ea01c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +313526 0x8465dac1172b6abe303bead4d06125aed72ea01c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +313724 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +313789 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +314190 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +314375 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005a +315698 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +315705 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +315780 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +316726 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +316726 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +316747 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317179 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317522 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000abad6ec946eff02b22e4050b3209da87380b3cbd 0x0000000000000000000000000000000000000000000000000000000000000002 +317522 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000002 +317526 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317536 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000003 +317536 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000003 +317567 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317567 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317588 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317597 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +317597 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +317606 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317610 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +317610 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317610 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +317643 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317643 0x1c776e19850998177a7e33f6496c368bcabdce54 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317646 0x1c776e19850998177a7e33f6496c368bcabdce54 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317646 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317660 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000004 +317660 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000004 +317957 0x8465dac1172b6abe303bead4d06125aed72ea01c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +318030 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318032 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318033 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000000 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +318033 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000000 +318034 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318036 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318036 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318063 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000001 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318063 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f 0x0000000000000000000000000000000000000000000000000000000000000001 +318074 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000000 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 +318074 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000000 +318096 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000002 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +318096 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000002 +318137 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +318528 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000003 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 +318528 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f 0x0000000000000000000000000000000000000000000000000000000000000003 +318627 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000004 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +318627 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000004 +318639 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0x17af63cbc1fd2f415358d4edda52ede90159c09397285dcedaecb33c5a6d5e02 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318639 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0x82add6dcb5f515082d024c78eb6496fd6d7e1a037e33403f23188b6c568336e8 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318650 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0x82add6dcb5f515082d024c78eb6496fd6d7e1a037e33403f23188b6c568336e8 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318653 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0xc0c8fdc5261cd471b4cf986e1dc55c83e67bab22ff35c3a1e32ab700b8b7eef7 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318904 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +319523 0x7b6556b40a5a4d40118387495314f4445986239c 0x6c2b4666ba8da5a95717621d879a77de725f3d816709b9cbe9f059b8f875e284 +321346 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +321884 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +321900 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +322038 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322041 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322043 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322047 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322048 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322056 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322059 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000005 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +322059 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000005 +322083 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322090 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322108 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000002 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322108 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000002 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000003 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000003 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000005 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000005 +322122 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000001 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322122 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000001 +322128 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000004 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322128 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000004 +322454 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x63726f0000000000000000000000000000000000000000000000000000000000 +322509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x63726f0000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000d388d8671ac6edb904d91c1585dedbd6895b9ef8 +322509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x63726f0000000000000000000000000000000000000000000000000000000000 +322550 0x8465dac1172b6abe303bead4d06125aed72ea01c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +322749 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000006 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +322749 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000006 +322750 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x41756374696f6e00000000000000000000000000000000000000000000000000 +322752 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x41756374696f6e00000000000000000000000000000000000000000000000000 0x000000000000000000000000fd5c601a0d48ad075724af920a83b907d24620dd +322752 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x41756374696f6e00000000000000000000000000000000000000000000000000 +322758 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f727467616765000000000000000000000000000000000000000000000000 +322760 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4d6f727467616765000000000000000000000000000000000000000000000000 0x000000000000000000000000f32d6e7a9ae9c3d59b642fcfa95c0f03c0706561 +322760 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f727467616765000000000000000000000000000000000000000000000000 +322764 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x457363726f770000000000000000000000000000000000000000000000000000 +322765 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x457363726f770000000000000000000000000000000000000000000000000000 0x000000000000000000000000091a096c2c75cd3bd6a80a8104a4c71a6f028483 +322765 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x457363726f770000000000000000000000000000000000000000000000000000 +322767 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x47756172616e7465650000000000000000000000000000000000000000000000 +322768 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x47756172616e7465650000000000000000000000000000000000000000000000 0x000000000000000000000000439061363c1502dcb8ce7b08dab39b5aa321adf2 +322768 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x47756172616e7465650000000000000000000000000000000000000000000000 +322774 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163747300000000000000000000000000000000000000 +322776 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53616665436f6e74726163747300000000000000000000000000000000000000 0x0000000000000000000000002e6bfa82463744c2b1254f119fa101bc924f6f0b +322776 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163747300000000000000000000000000000000000000 +322777 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163740000000000000000000000000000000000000000 +322777 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53616665436f6e74726163740000000000000000000000000000000000000000 0x0000000000000000000000009a5cb02980fbae601ed890f01d38be76a47d8eeb +322777 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163740000000000000000000000000000000000000000 +324029 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +324316 0x4d8875b5058c6bf9db0fba172114299eaa476a9d 0x8f38ec1c60ec4afc7e3dd2c41a94c0983104d82de715c0212bbfe4aca17ea3fb +324318 0x4d8875b5058c6bf9db0fba172114299eaa476a9d 0x5b6450564c0cb96f02986ab222d919319391faea73418fec4158904af177cdeb +324322 0x4d8875b5058c6bf9db0fba172114299eaa476a9d 0x80bb6e5f203cdbe2810b6446806301f07413ca83c2a9c7b0c1cc5b89853a55dd +325807 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +326760 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +326760 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +327103 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +327105 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +327227 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +327399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327544 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327544 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327690 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000041c32b2f3c0e04b20d2c4f1605f0abc33c3cad67 +327690 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000041c32b2f3c0e04b20d2c4f1605f0abc33c3cad67 +328002 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005b +328269 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +328529 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +328529 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +328585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000d51059a3dedfa8032a64361a883a53e26ed6941c +328585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000d51059a3dedfa8032a64361a883a53e26ed6941c +328870 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +328870 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +329480 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4368696e61000000000000000000000000000000000000000000000000000000 +329484 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4368696e61000000000000000000000000000000000000000000000000000000 0x00000000000000000000000080f3a701a57961f57752397d24a45f87127c361a +329484 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4368696e61000000000000000000000000000000000000000000000000000000 +329485 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329485 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329491 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329491 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329513 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329513 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329519 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329519 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329659 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5469636b65740000000000000000000000000000000000000000000000000000 +329659 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x5469636b65740000000000000000000000000000000000000000000000000000 0x0000000000000000000000009f26df964012d16fdea7485bd4b7042b3007e217 +329659 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5469636b65740000000000000000000000000000000000000000000000000000 +329667 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x446174696e670000000000000000000000000000000000000000000000000000 +329668 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x446174696e670000000000000000000000000000000000000000000000000000 0x000000000000000000000000f5f5d1595aa8eca29cfdc9b62357f01c33d9bf20 +329668 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x446174696e670000000000000000000000000000000000000000000000000000 +329673 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616e6479000000000000000000000000000000000000000000000000000000 +329673 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x43616e6479000000000000000000000000000000000000000000000000000000 0x000000000000000000000000f41830acc2a73021ff1c3381ac570b95d79d21d0 +329673 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616e6479000000000000000000000000000000000000000000000000000000 +329740 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005c +329749 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x57616c6c73747265657400000000000000000000000000000000000000000000 +329750 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x57616c6c73747265657400000000000000000000000000000000000000000000 0x0000000000000000000000002fed81f556a6f7478249fadbb68621467e21d38c +329750 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x57616c6c73747265657400000000000000000000000000000000000000000000 +329824 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000005c08761401d1a0904897c978787aa615a96e955c +329824 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000005c08761401d1a0904897c978787aa615a96e955c +329964 0xb8af70f84bfda39ccb2858f4fc54eca1b63dd519 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +330023 0xb8af70f84bfda39ccb2858f4fc54eca1b63dd519 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +330207 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000e0ed85f0cab17dba645bf4fe745ca29359c2c21b +330207 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000e0ed85f0cab17dba645bf4fe745ca29359c2c21b +330473 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000042244ccb6c7c889901960e60125ead7c2af685f8 +330473 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000042244ccb6c7c889901960e60125ead7c2af685f8 +330511 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +330511 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +330579 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000c550f754865b1ad138b660c9802ee8b039abb05b +330579 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000c550f754865b1ad138b660c9802ee8b039abb05b +330683 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000cffa3a1af763ccb260f4bf081f8a1bfddfdb89e0 +330683 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000cffa3a1af763ccb260f4bf081f8a1bfddfdb89e0 +330919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a4145a98b12b717078b96821124d781c563511ca +330919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a4145a98b12b717078b96821124d781c563511ca +331009 0x53bccda5dcacc0b10b7c4145b0aa6581330b8635 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +331542 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000003090aef28f1a9a4d1d9f9b8fc26d28ad1240214f +331542 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000003090aef28f1a9a4d1d9f9b8fc26d28ad1240214f +332007 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000aa3e4fd68c8fabd386fc571f9656e50dba5dd384 +332007 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000aa3e4fd68c8fabd386fc571f9656e50dba5dd384 +333256 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000009dca2265990b7ad9ac5c3a55157f1fc9d18381bc +333256 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000009dca2265990b7ad9ac5c3a55157f1fc9d18381bc +333294 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +333583 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000ff6c2227335eb7d5b29d86a8f78f35d4b9bafd3a +333583 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000ff6c2227335eb7d5b29d86a8f78f35d4b9bafd3a +333640 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000601ee21411eba5a5bc9d1c6298822a1a7b9e2286 +333640 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000601ee21411eba5a5bc9d1c6298822a1a7b9e2286 +334263 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000691ee952cf68d9abc488e42f5c1f95c020651333 +334263 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000691ee952cf68d9abc488e42f5c1f95c020651333 +334279 0xbd0edfbac386c9964f8f013d65d7dad5382d9cd7 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +334883 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005d +334915 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005e +334919 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005f +334919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000007d1ecf34b360f75280b83abc04f654ac99c7bd9c +334919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000007d1ecf34b360f75280b83abc04f654ac99c7bd9c +335076 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000367a3da4c3aa4c4b9de2c01bdca8075593c7ff1e +335076 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000367a3da4c3aa4c4b9de2c01bdca8075593c7ff1e +335348 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000009d8048c450677dcd0b6c37c6a989a54a2a506a27 +335348 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000009d8048c450677dcd0b6c37c6a989a54a2a506a27 +335643 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335649 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335649 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335652 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335684 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000d80b5d0763ceaf00e3c457c54acc880a6317d057 +335684 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000d80b5d0763ceaf00e3c457c54acc880a6317d057 +336089 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000866d22bf02ad128c2e015a27ed39c7f5f0bd65f3 +336089 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000866d22bf02ad128c2e015a27ed39c7f5f0bd65f3 +336231 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336234 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336242 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336243 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336244 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336245 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336245 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336247 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336248 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336255 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336260 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336263 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336264 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336266 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336266 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336334 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336336 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336337 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336338 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336439 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336451 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336452 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336453 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336453 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336461 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336495 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336497 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336497 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336497 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336507 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336509 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336510 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336510 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336510 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336518 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336520 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336521 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336522 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336526 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336527 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336528 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336528 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336543 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336543 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +337012 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000f2c453692a6f46cffd30943fe9bee65cac3622d7 +337012 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000f2c453692a6f46cffd30943fe9bee65cac3622d7 +337642 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x456475636174696f6e0000000000000000000000000000000000000000000000 +337642 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x456475636174696f6e0000000000000000000000000000000000000000000000 0x00000000000000000000000002ef13dd4479f121b4636bc3d7ea9da774b3ed74 +337642 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x456475636174696f6e0000000000000000000000000000000000000000000000 +337647 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50686f6e65000000000000000000000000000000000000000000000000000000 +337649 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x50686f6e65000000000000000000000000000000000000000000000000000000 0x0000000000000000000000003210743d3b82ec01338c50d64ce97de5e8ec94bb +337649 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50686f6e65000000000000000000000000000000000000000000000000000000 +337653 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506f6b6572000000000000000000000000000000000000000000000000000000 +337654 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x506f6b6572000000000000000000000000000000000000000000000000000000 0x000000000000000000000000d0dc4dac9c29cacd9dcd6d7f7ca97e04b0ba6e09 +337654 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506f6b6572000000000000000000000000000000000000000000000000000000 +337655 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50726f7065727479000000000000000000000000000000000000000000000000 +337656 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x50726f7065727479000000000000000000000000000000000000000000000000 0x00000000000000000000000097eb80f6d0777baa9bbcc8722b43e3e88d00efaf +337656 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50726f7065727479000000000000000000000000000000000000000000000000 +337663 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616c6573000000000000000000000000000000000000000000000000000000 +337663 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53616c6573000000000000000000000000000000000000000000000000000000 0x0000000000000000000000004ad03d890ef08dbae952527c829d0dde8d31c3b7 +337663 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616c6573000000000000000000000000000000000000000000000000000000 +337664 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d61726b65740000000000000000000000000000000000000000000000000000 +337669 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x486f757365000000000000000000000000000000000000000000000000000000 +337672 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x486f757365000000000000000000000000000000000000000000000000000000 0x0000000000000000000000000ec0d6547c59c38a9105525f0c10ec4d4a0b1afb +337672 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x486f757365000000000000000000000000000000000000000000000000000000 +337731 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000f80675f372ff20d0a5f3bc82a51c8fb9fb5022cd +337731 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000f80675f372ff20d0a5f3bc82a51c8fb9fb5022cd +338275 0x9f918d46c929f12a229b6084566384ee26805b4d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +338281 0x9f918d46c929f12a229b6084566384ee26805b4d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +338336 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +338424 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000008a66d1381b139ec676e522aeab6fd82cc78567d +338424 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000008a66d1381b139ec676e522aeab6fd82cc78567d +338435 0x8056338e73fde306bb5d9aedec7f4a7b8637c9e7 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +338439 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000065e9201879e2a6ff7da133f0c573a8fe5d9da7ca +338439 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000065e9201879e2a6ff7da133f0c573a8fe5d9da7ca +338661 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +338661 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +338991 0x0e5e2b9341341ade98f510ad9a744e01f3b29f03 0x1cf7652f1f9289dc41763c5bd36534c9772d48aa26021274d212f227d4b69765 0x0000000000000000000000000000000000000000000000000000000000000060 +339173 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000049f47bc027e273e21f46000c49971919b3e15773 +339173 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000049f47bc027e273e21f46000c49971919b3e15773 +339369 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000060 +339427 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000f3b83292f3e56f4aec1e3c44128d0f1a9d824559 +339427 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000f3b83292f3e56f4aec1e3c44128d0f1a9d824559 +340633 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x42697447656d7300000000000000000000000000000000000000000000000000 +340635 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x42697447656d7300000000000000000000000000000000000000000000000000 0x000000000000000000000000c34f6222062c65e35d4b0fc26d718738582118a6 +340635 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x42697447656d7300000000000000000000000000000000000000000000000000 +340653 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469616d6f6e6473000000000000000000000000000000000000000000000000 +340658 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4469616d6f6e6473000000000000000000000000000000000000000000000000 0x0000000000000000000000004e971507462271eadb8aac0d20312099f6d52947 +340658 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469616d6f6e6473000000000000000000000000000000000000000000000000 +340674 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x476f6c6400000000000000000000000000000000000000000000000000000000 +340675 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x476f6c6400000000000000000000000000000000000000000000000000000000 0x000000000000000000000000eb26edf39a4ad0a3b8d6a9804b4e2a7b47d3017b +340675 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x476f6c6400000000000000000000000000000000000000000000000000000000 +340685 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469676978000000000000000000000000000000000000000000000000000000 +340686 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4469676978000000000000000000000000000000000000000000000000000000 0x0000000000000000000000000b3765d911cbf67fd92f4d3e5cc25211ddc743de +340686 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469676978000000000000000000000000000000000000000000000000000000 +340700 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426f617264726f6f6d0000000000000000000000000000000000000000000000 +340700 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x426f617264726f6f6d0000000000000000000000000000000000000000000000 0x000000000000000000000000c8cfec0ee1d4802daaae1bebb07aa7c44931e633 +340700 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426f617264726f6f6d0000000000000000000000000000000000000000000000 +340708 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x45786368616e6765000000000000000000000000000000000000000000000000 +340710 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x45786368616e6765000000000000000000000000000000000000000000000000 0x0000000000000000000000005492f79ca66506bc751862ba35a9121d8b28532d +340710 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x45786368616e6765000000000000000000000000000000000000000000000000 +340712 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e00000000000000000000000000000000000000000000000000 +340713 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x426974636f696e00000000000000000000000000000000000000000000000000 0x000000000000000000000000a9033165b71f08ac82c53d5f982b463ca5301c15 +340713 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e00000000000000000000000000000000000000000000000000 +340718 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e73000000000000000000000000000000000000000000000000 +340719 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x426974636f696e73000000000000000000000000000000000000000000000000 0x000000000000000000000000f301f8e2cc1bab42ced9902f1fcd1a25303823db +340719 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e73000000000000000000000000000000000000000000000000 +340727 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d61696c00000000000000000000000000000000000000000000000000000000 +340727 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4d61696c00000000000000000000000000000000000000000000000000000000 0x0000000000000000000000004143c2f1563da14b2c09559ef5144b4c6ca268fe +340727 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d61696c00000000000000000000000000000000000000000000000000000000 +340728 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x456d61696c000000000000000000000000000000000000000000000000000000 +340835 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +340988 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000008db600d7c92b0182ec527d8972d9e4d67d82e62a +340988 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000008db600d7c92b0182ec527d8972d9e4d67d82e62a +341695 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000351be7a8b083e7e3e3c16744a1fea3420064f60a +341695 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000351be7a8b083e7e3e3c16744a1fea3420064f60a +341985 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +341997 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342001 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342004 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342004 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342007 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342007 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342008 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342026 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342026 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342027 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342027 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342033 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342035 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342036 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342041 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342047 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +342047 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342047 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342053 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342053 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342080 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342080 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342080 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342101 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342107 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342107 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342111 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342111 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342115 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342118 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342118 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342125 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342125 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342140 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +342141 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342145 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342145 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342145 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342162 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342162 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342173 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342173 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342188 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342188 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342272 0x65eb93c4e0854e3b00a64cd18c176a7fd54dc50f 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342386 0x65eb93c4e0854e3b00a64cd18c176a7fd54dc50f 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342386 0x8056338e73fde306bb5d9aedec7f4a7b8637c9e7 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342399 0x65eb93c4e0854e3b00a64cd18c176a7fd54dc50f 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342466 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000014a986e0b8943efe13e2f3514878dcd1fe08a677 +342466 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000014a986e0b8943efe13e2f3514878dcd1fe08a677 +342601 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342601 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342616 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +342618 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +342924 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000144c12d635ded35f0e0576564b95cf08045cb3ee +342924 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000144c12d635ded35f0e0576564b95cf08045cb3ee +342964 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000c36d3ccea8fb30b8f2c66af05bc3b5433d59168d +342964 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000c36d3ccea8fb30b8f2c66af05bc3b5433d59168d +343006 0x4bcd0591897025a0c42d500b4c37b11de6d96a3c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +343021 0x4bcd0591897025a0c42d500b4c37b11de6d96a3c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +343059 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +343079 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +343079 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +343083 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000006fa4aa0d8ce57b5325b1d04708db281bbe95b23b +343083 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000006fa4aa0d8ce57b5325b1d04708db281bbe95b23b +343133 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +343162 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000061 +343185 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000062 +343339 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000b9e893dc7da0b5b3eb9678d4860fb885f92be9cf +343339 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000b9e893dc7da0b5b3eb9678d4860fb885f92be9cf +343946 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +343966 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +343971 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +344121 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344121 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344164 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344164 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344839 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000001c3b909facd70e74c5697f1329c2d0cc0dd5ac3e +344839 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000001c3b909facd70e74c5697f1329c2d0cc0dd5ac3e +345506 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +346112 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346112 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346392 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346395 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346398 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346425 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346448 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346451 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346454 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346464 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346466 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +347014 0xd2d8d510980ef02fb2c3b79479d9b57d3bc7e2e7 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +347301 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347301 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347333 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347333 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347613 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x4c13017ee95afc4bbd8a701dd9fbc9733f1f09f5a1b5438b5b9abd48e4c92d78 0x5858585858585858580000000000000000000000000000000000000000000000 0x0000000000000000000000000075f6703dad72b3e89f3243b2666a7f1bd815c0 +347700 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +347705 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +347711 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +347711 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +347853 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +347953 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +347958 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +347958 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +347960 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +347960 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +348019 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +348244 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000fae49cd796d28e8eca3fd701f86864940270a6fe +348244 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000fae49cd796d28e8eca3fd701f86864940270a6fe +348443 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000001819c2a9ff0b2ebdc677b6e8f4ee5c2bd6b73dae +348443 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000001819c2a9ff0b2ebdc677b6e8f4ee5c2bd6b73dae +348675 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000fc039dc8cdba96ab8ceb01c972375b71ddcc6b2e +348675 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000fc039dc8cdba96ab8ceb01c972375b71ddcc6b2e +348743 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +348936 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000b3303a4f7ef21aed2325856caa14417e91ee5404 +348936 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000b3303a4f7ef21aed2325856caa14417e91ee5404 +350544 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +351473 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +353157 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +353181 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +353196 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +353196 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +353273 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +353276 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +353359 0xe2d560cc321a4e09e182693d45a3836ffd27a1bd 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353359 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353360 0x991c5b56fffb2e45444b5fc5be9304ac9576849b 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353361 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000063 +353367 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000064 +353370 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000065 +353438 0x52c6b42c37818ee7d562b52396685710b19801ec 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353438 0xf9da1908cc2280578b2639e3a4576dc77624868b 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353443 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000066 +353447 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000067 +353479 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000aadd74f71770fbef7325860bce13cff05e3ad1c9 +353479 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000aadd74f71770fbef7325860bce13cff05e3ad1c9 +354071 0x36290e3f7c0e074a9e80cd6eb2f36b77411c19d7 0xa192e48a82f18ef1c93e722713426e5733e98d5b2858ba5c7457faf4a8297dab 0x000000000000000000000000b834e3edfc1a927bdcecb67a9d0eccbd752a5bb3 0x0000000000000000000000000000000000000000000000000000000000056917 +354151 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0x5ca1bad5a7f3ee229aa045a13d9936a9a5f7f70067a0e39bdb8a6c0086b1544c 0xb56c4a1a61178e44bb3c424e54fccd7a48926c8ee43735cfa297f51c116344f1 +354162 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62 0x000000000000000000000000d3cda913deb6f67967b99d67acdfa1712c293601 0x000000000000000000000000afbc7cedd81c694e8033b101a0b49bfc1e5176e2 +354233 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0xed1062ba7ed13514b41ef115d3c324f50dcd644da75ee5659e9ae97071774f1e 0x000000000000000000000000b834e3edfc1a927bdcecb67a9d0eccbd752a5bb3 0xb56c4a1a61178e44bb3c424e54fccd7a48926c8ee43735cfa297f51c116344f1 +354585 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0x884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364 0x000000000000000000000000afbc7cedd81c694e8033b101a0b49bfc1e5176e2 +354866 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000009b75587d8d49477de8b6e845ccb40d970bf8701a +354866 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000009b75587d8d49477de8b6e845ccb40d970bf8701a +356461 0x84be9f9c3e3dc0721d628a3b8ef55fbe096c0495 0x0000000000000000000000000000000000000000000000000000000000000060 +356488 0xf0ea74d3e2743e880dcf12e731d6bdd5788a548c 0xf2fb068683a2e3c90600f0aab753f44a2340e65156afd0f69518d72b55354ece 0x0000000000000000000000000000000000000000000000000000000000000060 +356513 0x69e3eab0a888f72c161d1f2e4e97eb8f0089af88 0x3fbfa2086703ed2c0e6065c0a6d81aa1ffdf01229d542d9f132b6696db6c66f1 0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 +356526 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +356535 0xaf40044f727b3975174ed30d21a850b2f8619f11 0x7465737400000000000000000000000000000000000000000000000000000000 +356543 0xaf40044f727b3975174ed30d21a850b2f8619f11 0x3963323266663566323166306238316231313365363366376462366461393466 +357195 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +357195 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +357579 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357588 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357590 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +357590 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +357592 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357600 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357622 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357630 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +358290 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +358290 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +358426 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +358556 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +358556 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +358811 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000b76246acebd335e1af9e2073f684ff6c555816c6 +358811 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000b76246acebd335e1af9e2073f684ff6c555816c6 +359114 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +359114 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +359375 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000068 +359378 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000069 +359378 0x4d6387f3b967da39b11de111158d49754c31985d 0x2dba1d9e78f3192742fc9d510383d669fe8a4fa03d039bd7382ef67119078af7 0x0000000000000000000000000000000000000000000000000000000000000012 +359538 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006a +361585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361588 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361588 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361732 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000030d9803d6754bd9ad6d3a9990ca7a07af8745d5a +361732 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000030d9803d6754bd9ad6d3a9990ca7a07af8745d5a +361757 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +361757 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +361775 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +362002 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000013a85703f391b8c9abb8068be03ff4d6aebd11eb +362002 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000013a85703f391b8c9abb8068be03ff4d6aebd11eb +365791 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +365793 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006b +369141 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000006407c4286dc1c84aab28720eea596212c026450e +369141 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000006407c4286dc1c84aab28720eea596212c026450e +369239 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369249 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369253 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369259 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369261 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369263 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369274 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369426 0xe2d560cc321a4e09e182693d45a3836ffd27a1bd 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +369426 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +369428 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006c +369428 0x4d6387f3b967da39b11de111158d49754c31985d 0x2dba1d9e78f3192742fc9d510383d669fe8a4fa03d039bd7382ef67119078af7 0x0000000000000000000000000000000000000000000000000000000000000013 +369431 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006d +369538 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +369540 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006e +370399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000071dcbc554dada022fdd31333f8883e953240f0b0 +370399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000071dcbc554dada022fdd31333f8883e953240f0b0 +370517 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +370517 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +370545 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +370545 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371190 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371280 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371286 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371288 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371299 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371307 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371327 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371327 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371329 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371352 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371360 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371362 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371369 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371378 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371378 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371450 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371450 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371489 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371489 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371509 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371509 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371532 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371658 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371658 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371660 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371876 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371876 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371904 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371904 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371906 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371912 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371912 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371914 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371918 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371918 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371931 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371931 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371933 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371938 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371938 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371940 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371973 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371973 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +372006 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +372006 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +372014 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +372847 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +374209 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +374225 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +374365 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +374388 0x7fb091d48426f54f6fb8d1a43f8e33f80454f4e3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +375079 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +375079 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +375093 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +375401 0x4bca74810cc4917a7dee954d21221b72fd87d3d7 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +375440 0x4bca74810cc4917a7dee954d21221b72fd87d3d7 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +375447 0x4bca74810cc4917a7dee954d21221b72fd87d3d7 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +376493 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +376573 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376588 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376644 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376650 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376668 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +376906 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +377026 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377026 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377139 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377139 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +377506 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +377523 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +377523 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +377525 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +377581 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +377586 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006f +377608 0x8465dac1172b6abe303bead4d06125aed72ea01c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +377627 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377627 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +377629 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377629 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +377703 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377703 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +377730 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377730 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377746 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377877 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +377877 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377894 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377905 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +377905 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377917 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377917 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +377922 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377922 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +377925 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +378345 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +378345 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +378347 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +378347 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +379027 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000070 +379032 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000071 +379039 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000072 +379158 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x77656c6661726500000000000000000000000000000000000000000000000000 +379161 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x77656c6661726500000000000000000000000000000000000000000000000000 0x000000000000000000000000266d8a3bfa7536f3f921da30824e47c561dd66cc +379161 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x77656c6661726500000000000000000000000000000000000000000000000000 +379163 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x736f636965747900000000000000000000000000000000000000000000000000 +379164 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x736f636965747900000000000000000000000000000000000000000000000000 0x000000000000000000000000435a8f8bbed708ca75aa1c8ca7091fa1a3c03782 +379164 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x736f636965747900000000000000000000000000000000000000000000000000 +379167 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461707000000000000000000000000000000000000000000000000000000000 +379170 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +379171 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6461707000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000f81f0d1f4cacb0a419dba6fa897a121f61347c84 +379171 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461707000000000000000000000000000000000000000000000000000000000 +379172 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6e6574776f726b00000000000000000000000000000000000000000000000000 +379176 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6e6574776f726b00000000000000000000000000000000000000000000000000 0x00000000000000000000000030ce983f55cfa6742a1270e263ff33010fb82790 +379176 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6e6574776f726b00000000000000000000000000000000000000000000000000 +379180 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7765697472616465720000000000000000000000000000000000000000000000 +379182 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x7765697472616465720000000000000000000000000000000000000000000000 0x00000000000000000000000003477c75a6b22c58f8e65ecfb97219541c16aacf +379182 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7765697472616465720000000000000000000000000000000000000000000000 +379210 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7065657200000000000000000000000000000000000000000000000000000000 +379212 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x7065657200000000000000000000000000000000000000000000000000000000 0x000000000000000000000000a5fcbfe7e0fe1a8f97772e3ff2433df651c3cd40 +379212 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7065657200000000000000000000000000000000000000000000000000000000 +379214 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c65646765720000000000000000000000000000000000000000000000000000 +379216 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6c65646765720000000000000000000000000000000000000000000000000000 0x0000000000000000000000001bfa9c5206cf2f2d6218468200da6a6b2488f5f1 +379216 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c65646765720000000000000000000000000000000000000000000000000000 +379217 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6964656e74697479000000000000000000000000000000000000000000000000 +379219 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6964656e74697479000000000000000000000000000000000000000000000000 0x000000000000000000000000420ec54a21967d9813cd184fa32783b61897b097 +379219 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6964656e74697479000000000000000000000000000000000000000000000000 +379220 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x72657075746174696f6e00000000000000000000000000000000000000000000 +379224 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x72657075746174696f6e00000000000000000000000000000000000000000000 0x000000000000000000000000d9b2f59f3b5c7b3c67047d2f03c3e8052470be92 +379224 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x72657075746174696f6e00000000000000000000000000000000000000000000 +379235 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c6f747465727900000000000000000000000000000000000000000000000000 +379237 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6c6f747465727900000000000000000000000000000000000000000000000000 0x0000000000000000000000001f6cc3f7c927e1196c03ac49c5aff0d39c9d103d +379237 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c6f747465727900000000000000000000000000000000000000000000000000 +381271 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +381271 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +381276 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +381689 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +382200 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000073 +382217 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000074 +382644 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +382644 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +383284 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383337 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383354 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383361 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383427 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +383466 0x7f1d234e281ff8421b2b0650a9b8f85b5d73bd59 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383469 0x51b6b4f5b270fa093198a984c3fce5ea607a94e7 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383515 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +383519 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +383630 0x513d9cfdf8c3f7c08006a4828e9319bafff2e556 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383760 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +383802 0x04a163c9e3cadc6341ac0340403b42c83e384832 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383815 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +383815 0xce4484b6d988a27ec9da967f84320c89194dd56b 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383844 0x285b28d0c11c5bd3a039f3c26c887e2f8f177dc6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383852 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +383852 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383859 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +383859 0xbf871ee17553ca56382a0dda5256760a0a979e62 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +383864 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +383864 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +383968 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +383968 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +383973 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +384127 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +384138 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384149 0x285b28d0c11c5bd3a039f3c26c887e2f8f177dc6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384173 0x285b28d0c11c5bd3a039f3c26c887e2f8f177dc6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +384173 0x81e4c09f8d140521e2265b42d99fc2fb868a5b14 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384301 0x03131e9dc0d42f57c92c3ae39e79a9abac75d9bb 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384422 0x4e96c7985c2f260ae9fdd12fd7f78364f16af2ce 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384506 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384511 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384546 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +384771 0xac4df82fe37ea2187bc8c011a23d743b4f39019a 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384825 0xac4df82fe37ea2187bc8c011a23d743b4f39019a 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +384861 0x9dfb24cf9ef6b885a7d130b5a92002985954b8e6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384917 0x4e96c7985c2f260ae9fdd12fd7f78364f16af2ce 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384923 0xe291a9e17fd310b860f665dbdd8375144bdd6ecd 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384965 0xc833e49ac9d0315778d616cbb583a8b1b3bf2d73 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +385067 0x3a360d9e2919714547623e4bc9504242b816d2d8 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +385073 0x3a360d9e2919714547623e4bc9504242b816d2d8 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +385356 0xe291a9e17fd310b860f665dbdd8375144bdd6ecd 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +385356 0xc833e49ac9d0315778d616cbb583a8b1b3bf2d73 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +386571 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +386620 0xdcf421d093428b096ca501a7cd1a740855a7976f +386736 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000000 +386786 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000001 +386795 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000002 +386804 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000003 +386812 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000004 +386818 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000005 +386899 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000006 +386939 0x523c43c44671e34c1e7a9a619420b191fb009db1 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000000 +386945 0x7ff1fa4c4bb95760dda000b5856bc22db681e989 0x0000000000000000000000000000000000000000000000000000000000000000 +386975 0xc48d9595221e591bf7a785591f928b6df08fee7a 0x0000000000000000000000000000000000000000000000000000000000000000 +387011 0x07f1d608c18dc12e6ee4487be4d01571315dbef1 0x0000000000000000000000000000000000000000000000000000000000000000 +387014 0x07f1d608c18dc12e6ee4487be4d01571315dbef1 0x0000000000000000000000000000000000000000000000000000000000000001 +387016 0xa72cd306bd6bc58922dcfed48cb1474f323860a9 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387032 0x07f1d608c18dc12e6ee4487be4d01571315dbef1 0x0000000000000000000000000000000000000000000000000000000000000002 +387044 0x91b876c8614495fb9272a95edecc92938e5e2da6 0x0000000000000000000000000000000000000000000000000000000000000000 +387045 0xa72cd306bd6bc58922dcfed48cb1474f323860a9 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387206 0x680a79579b69df391a4d23a7ba219b4d020736dc 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387225 0x680a79579b69df391a4d23a7ba219b4d020736dc 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387241 0x680a79579b69df391a4d23a7ba219b4d020736dc 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387276 0x680a79579b69df391a4d23a7ba219b4d020736dc 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +387276 0x4b94fb373ec3a87f79f6de32ad730806020c94f1 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387284 0x680a79579b69df391a4d23a7ba219b4d020736dc 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +387365 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387615 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387627 0x2a31114378a3093d29aa387bfe3829d9f1f4c2a8 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387641 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +387648 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387654 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387654 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +387658 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387658 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +387683 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387688 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387688 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +387690 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387690 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +387761 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +388108 0x33921ef3eeffb23d68802e43e8110ab6c2fff774 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388111 0xbec795614eda3b5ccd2e32070b4ace745ce801c4 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388150 0xbec795614eda3b5ccd2e32070b4ace745ce801c4 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388246 0xed6523382d41982604b845e5b94dd7fa0060198d 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388285 0x329e2382db65ef312ca68a6c8ef549e68d051e06 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388296 0xed6523382d41982604b845e5b94dd7fa0060198d 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388516 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388860 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388893 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388893 0xf2d850b176ddf0b6c1411d68ef96d2d8b7b0b480 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388894 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388907 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +388907 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388909 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388912 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +388912 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +388918 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +388918 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +388923 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388923 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388940 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388971 0x2a31114378a3093d29aa387bfe3829d9f1f4c2a8 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +388990 0x892140413344e49d9eaf54db38126d973fa167f6 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +389012 0x892140413344e49d9eaf54db38126d973fa167f6 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +389158 0x892140413344e49d9eaf54db38126d973fa167f6 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +389206 0xe358b3b9f29c67cb810c5184e6fde27d66ce036c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389238 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +389277 0x534c5a8c34ad4e150581c50ded1bbfa5f22b1800 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389292 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389301 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +389301 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +389309 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +389324 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +389324 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389328 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +389343 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +389343 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +390001 0xecc72aac2791ee973bf607781a33a341b41e58c0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390004 0xecc72aac2791ee973bf607781a33a341b41e58c0 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +390024 0xd5babb9f28a9e7c78735c9c955d5626159f1be70 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390042 0xd5babb9f28a9e7c78735c9c955d5626159f1be70 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390236 0x54dcd97a77d12fb42a9ef839a3cdba0c1e92841a 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390306 0xecc72aac2791ee973bf607781a33a341b41e58c0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390867 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +391685 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +391690 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +391691 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +391697 0xe358b3b9f29c67cb810c5184e6fde27d66ce036c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +391713 0x534c5a8c34ad4e150581c50ded1bbfa5f22b1800 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +391849 0x534c5a8c34ad4e150581c50ded1bbfa5f22b1800 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +392002 0x81e4c09f8d140521e2265b42d99fc2fb868a5b14 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +392097 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +392104 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +392110 0xa076155806214a73f37f5fcd8025036d92f6a3fb +392294 0xac9560da030bc57c70c90274d8ffe4ba6aea1846 0x0000000000000000000000000000000000000000000000000000000000000000 +392697 0xc4395759e26469baa0e6421bdc1d0232c6f4b6c3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +392960 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +392970 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +392990 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +393302 0x8ec0d0bbce4349e2d34586e2de392caa73532d3f 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +393370 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +393752 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +393752 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +394354 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +394389 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394389 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394390 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394390 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394390 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394391 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394393 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394393 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394394 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394395 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394426 0xdb30622d51e8d6221f0b1cbde57d4734387d7ca1 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394800 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000075 +395595 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000d1f35f7250a922150c0e879eaf0cb5f0f7dd47c3 +395595 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000d1f35f7250a922150c0e879eaf0cb5f0f7dd47c3 +395969 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +396348 0xc4395759e26469baa0e6421bdc1d0232c6f4b6c3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +397108 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 +397588 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 +397591 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 +398412 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +398412 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +398456 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +398477 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +398679 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +398968 0xe82f5f7db7bf9bad426505c654e8d13b609f527c 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +398972 0x6f7ff1690f64973fffc848f5cf101b446acb1c27 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +399058 0x6f7ff1690f64973fffc848f5cf101b446acb1c27 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +399804 0xc4395759e26469baa0e6421bdc1d0232c6f4b6c3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +399849 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs index b511365cf..ec78ce48e 100644 --- a/ethcore/src/chainfilter/tests.rs +++ b/ethcore/src/chainfilter/tests.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::collections::HashMap; +use std::io::{BufRead, BufReader, Read}; use std::str::FromStr; use util::hash::*; use util::sha3::*; @@ -47,9 +48,9 @@ impl FilterDataSource for MemoryCache { } } -fn topic_to_bloom(topic: &H256) -> H2048 { +fn to_bloom(hashable: &T) -> H2048 where T: Hashable { let mut bloom = H2048::new(); - bloom.shift_bloomed(&topic.sha3()); + bloom.shift_bloomed(&hashable.sha3()); bloom } @@ -64,7 +65,7 @@ fn test_topic_basic_search() { let modified_blooms = { let filter = ChainFilter::new(&cache, index_size, bloom_levels); let block_number = 23; - filter.add_bloom(&topic_to_bloom(&topic), block_number) + filter.add_bloom(&to_bloom(&topic), block_number) }; // number of modified blooms should always be equal number of levels @@ -73,27 +74,111 @@ fn test_topic_basic_search() { { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 0, 100); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 100); assert_eq!(blocks.len(), 1); assert_eq!(blocks[0], 23); } { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 0, 23); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 23); assert_eq!(blocks.len(), 0); } { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 23, 24); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 23, 24); assert_eq!(blocks.len(), 1); assert_eq!(blocks[0], 23); } { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_bloom(&topic_to_bloom(&topic), 24, 100); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 24, 100); assert_eq!(blocks.len(), 0); } } + +fn for_each_bloom(bytes: &[u8], mut f: F) where F: FnMut(usize, &H2048) { + let mut reader = BufReader::new(bytes); + let mut line = String::new(); + while reader.read_line(&mut line).unwrap() > 0 { + { + let mut number_bytes = vec![]; + let mut bloom_bytes = [0; 512]; + + let mut line_reader = BufReader::new(line.as_ref() as &[u8]); + line_reader.read_until(b' ', &mut number_bytes).unwrap(); + line_reader.consume(2); + line_reader.read_exact(&mut bloom_bytes).unwrap(); + + let number = String::from_utf8(number_bytes).map(|s| s[..s.len() -1].to_owned()).unwrap().parse::().unwrap(); + let bloom = H2048::from_str(&String::from_utf8(bloom_bytes.to_vec()).unwrap()).unwrap(); + f(number, &bloom); + } + line.clear(); + } +} + +fn for_each_log(bytes: &[u8], mut f: F) where F: FnMut(usize, &Address, &[H256]) { + let mut reader = BufReader::new(bytes); + let mut line = String::new(); + while reader.read_line(&mut line).unwrap() > 0 { + { + let mut number_bytes = vec![]; + let mut address_bytes = [0;42]; + let mut topic = [0;66]; + let mut topics_bytes = vec![]; + + let mut line_reader = BufReader::new(line.as_ref() as &[u8]); + line_reader.read_until(b' ', &mut number_bytes).unwrap(); + line_reader.read_exact(&mut address_bytes).unwrap(); + line_reader.consume(1); + while let Ok(_) = line_reader.read_exact(&mut topic) { + line_reader.consume(1); + topics_bytes.push(topic.to_vec()); + } + + let number = String::from_utf8(number_bytes).map(|s| s[..s.len() -1].to_owned()).unwrap().parse::().unwrap(); + let address = Address::from_str(&String::from_utf8(address_bytes.to_vec()).map(|a| a[2..].to_owned()).unwrap()).unwrap(); + let topics: Vec = topics_bytes + .into_iter() + .map(|t| H256::from_str(&String::from_utf8(t).map(|t| t[2..].to_owned()).unwrap()).unwrap()) + .collect(); + f(number, &address, &topics); + } + line.clear(); + } +} + +// tests chain filter on real data between blocks 300_000 and 400_000 +#[test] +fn test_chainfilter_real_data() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + + for_each_bloom(include_bytes!("blooms.txt"), | block_number, bloom | { + let modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + filter.add_bloom(bloom, block_number) + }; + + // number of modified blooms should always be equal number of levels + assert_eq!(modified_blooms.len(), bloom_levels as usize); + cache.insert_blooms(modified_blooms); + }); + + for_each_log(include_bytes!("logs.txt"), | block_number, address, topics | { + println!("block_number: {:?}", block_number); + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(address), block_number, block_number + 1); + assert_eq!(blocks.len(), 1); + for (i, topic) in topics.iter().enumerate() { + println!("topic: {:?}", i); + let blocks = filter.blocks_with_bloom(&to_bloom(topic), block_number, block_number + 1); + assert_eq!(blocks.len(), 1); + } + }); +} From 64913d5009816e23adff19fdb96e402baa8f6952 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Feb 2016 21:43:30 +0100 Subject: [PATCH 031/753] Additional address filter --- util/src/network/discovery.rs | 6 +++++- util/src/network/host.rs | 8 ++++---- util/src/network/node_table.rs | 7 +++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 08f5e5cf1..8ed49b274 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -356,7 +356,11 @@ impl Discovery { } let mut entry = NodeEntry { id: node.clone(), endpoint: source.clone() }; if !entry.endpoint.is_valid() { - debug!(target: "discovery", "Bad address: {:?}", entry); + debug!(target: "discovery", "Got bad address: {:?}, using {:?} instead", entry, from); + entry.endpoint.address = from.clone(); + } + if !entry.endpoint.is_global() { + debug!(target: "discovery", "Got local address: {:?}, using {:?} instead", entry, from); entry.endpoint.address = from.clone(); } self.update_node(entry.clone()); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index c548d07cf..806ef2b92 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -39,7 +39,7 @@ use network::{NetworkProtocolHandler, PROTOCOL_VERSION}; use network::node_table::*; use network::stats::NetworkStats; use network::error::DisconnectReason; -use igd::{PortMappingProtocol,search_gateway}; +use igd::{PortMappingProtocol, search_gateway}; use network::discovery::{Discovery, TableUpdates, NodeEntry}; type Slab = ::slab::Slab; @@ -105,12 +105,12 @@ impl NetworkConfiguration { if self.nat_enabled { info!("Enabling NAT..."); match search_gateway() { - Err(ref err) => info!("Error: {}", err), + Err(ref err) => warn!("Port mapping error: {}", err), Ok(gateway) => { let int_addr = SocketAddrV4::from_str("127.0.0.1:30304").unwrap(); match gateway.get_any_address(PortMappingProtocol::TCP, int_addr, 0, "Parity Node/TCP") { Err(ref err) => { - info!("There was an error! {}", err); + warn!("Port mapping error: {}", err); }, Ok(ext_addr) => { info!("Local gateway: {}, External ip address: {}", gateway, ext_addr); @@ -356,7 +356,7 @@ impl Host where Message: Send + Sync + Clone { }, |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; - let endpoint = NodeEndpoint { address: addr.clone(), udp_port: addr.port() }; + let endpoint = NodeEndpoint { address: config.public_address.clone(), udp_port: addr.port() }; let discovery = Discovery::new(&keys, endpoint, DISCOVERY); let path = config.config_path.clone(); let mut host = Host:: { diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index 69d12dc87..c152efd4f 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -96,6 +96,13 @@ impl NodeEndpoint { SocketAddr::V6(a) => !a.ip().is_unspecified() } } + + pub fn is_global(&self) -> bool { + match self.address { + SocketAddr::V4(a) => a.ip().is_global(), + SocketAddr::V6(a) => a.ip().is_global() + } + } } impl FromStr for NodeEndpoint { From 0a3e8a0fdbbed91b52fc239ec7668f614fc1c17f Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 15 Feb 2016 21:56:33 +0100 Subject: [PATCH 032/753] more tests for bloomfilter --- ethcore/src/chainfilter/tests.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs index ec78ce48e..2eb6275ea 100644 --- a/ethcore/src/chainfilter/tests.rs +++ b/ethcore/src/chainfilter/tests.rs @@ -153,7 +153,7 @@ fn for_each_log(bytes: &[u8], mut f: F) where F: FnMut(usize, &Address, &[H25 // tests chain filter on real data between blocks 300_000 and 400_000 #[test] -fn test_chainfilter_real_data() { +fn test_chainfilter_real_data_short_searches() { let index_size = 16; let bloom_levels = 3; @@ -182,3 +182,32 @@ fn test_chainfilter_real_data() { } }); } + +// tests chain filter on real data between blocks 300_000 and 400_000 +#[test] +fn test_chainfilter_real_data_single_search() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + + for_each_bloom(include_bytes!("blooms.txt"), | block_number, bloom | { + let modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + filter.add_bloom(bloom, block_number) + }; + + // number of modified blooms should always be equal number of levels + assert_eq!(modified_blooms.len(), bloom_levels as usize); + cache.insert_blooms(modified_blooms); + }); + + let address = Address::from_str("c4395759e26469baa0e6421bdc1d0232c6f4b6c3").unwrap(); + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(&address), 300_000, 400_000); + // bloom may return more blocks, but our log density is low, so it should be fine + assert_eq!(blocks.len(), 3); + assert_eq!(blocks[0], 392697); + assert_eq!(blocks[1], 396348); + assert_eq!(blocks[2], 399804); +} From 734652d9134127579928012fb9ec8fd4f55abb19 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 16 Feb 2016 00:56:25 +0300 Subject: [PATCH 033/753] work in progress --- util/src/keys/directory.rs | 46 +++++++++++++++++---------- util/src/keys/encryptor.rs | 65 ++++++++++++++++++++++++++++++++++++++ util/src/keys/mod.rs | 2 ++ util/src/lib.rs | 1 + 4 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 util/src/keys/encryptor.rs diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index c5e17100f..23e82d010 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -425,17 +425,17 @@ enum KeyFileLoadError { pub struct KeyDirectory { /// Directory path for key management. path: String, - cache: HashMap, - cache_usage: VecDeque, + cache: RefCell>, + cache_usage: RefCell>, } impl KeyDirectory { /// Initializes new cache directory context with a given `path` pub fn new(path: &Path) -> KeyDirectory { KeyDirectory { - cache: HashMap::new(), + cache: RefCell::new(HashMap::new()), path: path.to_str().expect("Initialized key directory with empty path").to_owned(), - cache_usage: VecDeque::new(), + cache_usage: RefCell::new(VecDeque::new()), } } @@ -448,25 +448,34 @@ impl KeyDirectory { let json_bytes = json_text.into_bytes(); try!(file.write(&json_bytes)); } + let mut cache = self.cache.borrow_mut(); let id = key_file.id.clone(); - self.cache.insert(id.clone(), key_file); + cache.insert(id.clone(), key_file); Ok(id.clone()) } /// Returns key given by id if corresponding file exists and no load error occured. /// Warns if any error occured during the key loading - pub fn get(&mut self, id: &Uuid) -> Option<&KeyFileContent> { + pub fn get(&self, id: &Uuid) -> Option> { let path = self.key_path(id); - self.cache_usage.push_back(id.clone()); - Some(self.cache.entry(id.to_owned()).or_insert( + { + let mut usage = self.cache_usage.borrow_mut(); + usage.push_back(id.clone()); + } + + if !self.cache.borrow().contains_key(id) { match KeyDirectory::load_key(&path) { - Ok(loaded_key) => loaded_key, + Ok(loaded_key) => { + self.cache.borrow_mut().insert(id.to_owned(), loaded_key); + } Err(error) => { warn!(target: "sstore", "error loading key {:?}: {:?}", id, error); return None; } } - )) + } + + Some(Ref::map(self.cache.borrow(), |c| c.get(id).expect("should be they key, we have just inserted or checked it"))) } /// Returns current path to the directory with keys @@ -476,29 +485,32 @@ impl KeyDirectory { /// Removes keys that never been requested during last `MAX_USAGE_TRACK` times pub fn collect_garbage(&mut self) { - let total_usages = self.cache_usage.len(); + let mut cache_usage = self.cache_usage.borrow_mut(); + + let total_usages = cache_usage.len(); let untracked_usages = max(total_usages as i64 - MAX_CACHE_USAGE_TRACK as i64, 0) as usize; if untracked_usages > 0 { - self.cache_usage.drain(..untracked_usages); + cache_usage.drain(..untracked_usages); } - if self.cache.len() <= MAX_CACHE_USAGE_TRACK { return; } + let mut cache = self.cache.borrow_mut(); + if cache.len() <= MAX_CACHE_USAGE_TRACK { return; } - let uniqs: HashSet<&Uuid> = self.cache_usage.iter().collect(); + let uniqs: HashSet<&Uuid> = cache_usage.iter().collect(); let mut removes = HashSet::new(); - for key in self.cache.keys() { + for key in cache.keys() { if !uniqs.contains(key) { removes.insert(key.clone()); } } - for removed_key in removes { self.cache.remove(&removed_key); } + for removed_key in removes { cache.remove(&removed_key); } } /// Reports how many keys are currently cached. pub fn cache_size(&self) -> usize { - self.cache.len() + self.cache.borrow().len() } fn key_path(&self, id: &Uuid) -> PathBuf { diff --git a/util/src/keys/encryptor.rs b/util/src/keys/encryptor.rs new file mode 100644 index 000000000..cbc926dc6 --- /dev/null +++ b/util/src/keys/encryptor.rs @@ -0,0 +1,65 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Generic Encryptor + +use keys::directory::*; +use common::*; + +pub trait EncryptedHashMap { + // Returns existing value for the key, if any + fn get(&self, key: &Key, password: &str) -> Option; + // Insert new encrypted key-value and returns previous if there was any + fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; + // Removes key-value by key and returns the removed one, if any exists and password was provided + fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; + // Deletes key-value by key and returns if the key-value existed + fn delete(&mut self, key: &Key) -> bool { + self.remove::<()>(key, None).is_some() + } +} + +pub struct SecretStore { + directory: KeyDirectory +} + +impl EncryptedHashMap for SecretStore { + fn get(&self, key: &H128, password: &str) -> Option { + match self.directory.get(key) { + Some(key_file) => { + let mut instance = Value::default(); + instance.populate_raw(&key_file.crypto.cipher_text); + Some(instance) + }, + None => None + } + + } + + fn insert(&mut self, key: H128, value: Value, password: &str) -> Option{ + let previous = if let Some(key_file) = self.directory.get(&key) { self.get(&key, password) } else { None }; + previous + } + + fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { + let previous = match (self.directory.get(&key), password) { + (Some(key_file), Some(pass)) => self.get(&key, pass), + (_, _) => None + }; + previous + } + +} diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index d7ffdb0dd..f886d362c 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -17,3 +17,5 @@ //! Key management module pub mod directory; + +mod encryptor; diff --git a/util/src/lib.rs b/util/src/lib.rs index d4f972800..151afb60a 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -20,6 +20,7 @@ #![feature(associated_consts)] #![feature(plugin)] #![feature(catch_panic)] +#![feature(cell_extras)] // Clippy settings #![plugin(clippy)] // TODO [todr] not really sure From fb0b5b2e5ba49ed0799e9efed0978be3cf981273 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 00:22:44 +0100 Subject: [PATCH 034/753] Raise fd limit in linux --- util/fdlimit/src/raise_fd_limit.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/util/fdlimit/src/raise_fd_limit.rs b/util/fdlimit/src/raise_fd_limit.rs index f57ac2785..92127da35 100644 --- a/util/fdlimit/src/raise_fd_limit.rs +++ b/util/fdlimit/src/raise_fd_limit.rs @@ -57,5 +57,28 @@ pub unsafe fn raise_fd_limit() { } } -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(any(target_os = "linux"))] +#[allow(non_camel_case_types)] +pub unsafe fn raise_fd_limit() { + use libc; + use std::io; + + // Fetch the current resource limits + let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0}; + if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 { + let err = io::Error::last_os_error(); + panic!("raise_fd_limit: error calling getrlimit: {}", err); + } + + // Set soft limit to hard imit + rlim.rlim_cur = rlim.rlim_max; + + // Set our newly-increased resource limit + if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 { + let err = io::Error::last_os_error(); + panic!("raise_fd_limit: error calling setrlimit: {}", err); + } +} + +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] pub unsafe fn raise_fd_limit() {} From dbf3691c22870e7079d5976c19658c70232ad363 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 01:13:13 +0100 Subject: [PATCH 035/753] Return nothing on state requests instead of panicing --- ethcore/src/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 09f7417e8..03c470bdb 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -419,11 +419,11 @@ impl BlockChainClient for Client { } fn state_data(&self, _hash: &H256) -> Option { - unimplemented!(); + None } fn block_receipts(&self, _hash: &H256) -> Option { - unimplemented!(); + None } fn import_block(&self, bytes: Bytes) -> ImportResult { From 203947388b9f7fe6a6dda5e5e55c76c3fe66646a Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 02:05:36 +0100 Subject: [PATCH 036/753] Get public address/UPNP refactoring --- Cargo.lock | 1 + parity/main.rs | 40 ++++++++----- util/Cargo.toml | 1 + util/src/lib.rs | 1 + util/src/network/discovery.rs | 14 ++--- util/src/network/host.rs | 105 +++++++++++++++------------------- util/src/network/mod.rs | 1 + util/src/network/service.rs | 2 +- 8 files changed, 84 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c451a6477..2e38f5aeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,7 @@ dependencies = [ "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/parity/main.rs b/parity/main.rs index 903b471c5..5fec05eb4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -64,8 +64,8 @@ Options: -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --no-bootstrap Don't bother trying to connect to any nodes initially. - --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. - --public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304]. + --listen-address URL Specify the IP/port on which to listen for peers. + --public-address URL Specify the IP/port on which peers may connect. --address URL Equivalent to --listen-address URL --public-address URL. --upnp Use UPnP to try to figure out the correct network settings. --node-key KEY Specify node secret key as hex string. @@ -79,7 +79,12 @@ Options: -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. -", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option, flag_node_key: Option); +", flag_cache_pref_size: usize, + flag_cache_max_size: usize, + flag_address: Option, + flag_listen_address: Option, + flag_public_address: Option, + flag_node_key: Option); fn setup_log(init: &str) { let mut builder = LogBuilder::new(); @@ -155,21 +160,26 @@ impl Configuration { } } - fn net_addresses(&self) -> (SocketAddr, SocketAddr) { - let listen_address; - let public_address; + fn net_addresses(&self) -> (Option, Option) { + let mut listen_address = None; + let mut public_address = None; - match self.args.flag_address { - None => { - listen_address = SocketAddr::from_str(self.args.flag_listen_address.as_ref()).expect("Invalid listen address given with --listen-address"); - public_address = SocketAddr::from_str(self.args.flag_public_address.as_ref()).expect("Invalid public address given with --public-address"); + if let Some(ref a) = self.args.flag_address { + public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address")); + listen_address = public_address; + } + if let Some(ref a) = self.args.flag_listen_address { + if listen_address.is_some() { + panic!("Conflicting flags: --address and --listen-address"); } - Some(ref a) => { - public_address = SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address"); - listen_address = public_address; + listen_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --listen-address")); + } + if let Some(ref a) = self.args.flag_public_address { + if public_address.is_some() { + panic!("Conflicting flags: --address and --public-address"); } - }; - + public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --public-address")); + } (listen_address, public_address) } } diff --git a/util/Cargo.toml b/util/Cargo.toml index b1e9bbc1e..5bdf8c5a6 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -30,3 +30,4 @@ clippy = "0.0.41" json-tests = { path = "json-tests" } target_info = "0.1.0" igd = "0.4.2" +libc = "0.2.7" diff --git a/util/src/lib.rs b/util/src/lib.rs index 6dde49a01..7592cd17a 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -110,6 +110,7 @@ extern crate serde; #[macro_use] extern crate log as rlog; extern crate igd; +extern crate libc; pub mod standard; #[macro_use] diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 8ed49b274..c15dbbbc4 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -78,7 +78,7 @@ struct Datagramm { pub struct Discovery { id: NodeId, secret: Secret, - address: NodeEndpoint, + public_endpoint: NodeEndpoint, udp_socket: UdpSocket, token: StreamToken, discovery_round: u16, @@ -94,12 +94,12 @@ pub struct TableUpdates { } impl Discovery { - pub fn new(key: &KeyPair, address: NodeEndpoint, token: StreamToken) -> Discovery { - let socket = UdpSocket::bound(&address.udp_address()).expect("Error binding UDP socket"); + pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken) -> Discovery { + let socket = UdpSocket::bound(&listen).expect("Error binding UDP socket"); Discovery { id: key.public().clone(), secret: key.secret().clone(), - address: address, + public_endpoint: public, token: token, discovery_round: 0, discovery_id: NodeId::new(), @@ -199,7 +199,7 @@ impl Discovery { fn ping(&mut self, node: &NodeEndpoint) { let mut rlp = RlpStream::new_list(3); rlp.append(&PROTOCOL_VERSION); - self.address.to_rlp_list(&mut rlp); + self.public_endpoint.to_rlp_list(&mut rlp); node.to_rlp_list(&mut rlp); trace!(target: "discovery", "Sent Ping to {:?}", &node); self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain()); @@ -507,8 +507,8 @@ mod tests { let key2 = KeyPair::create().unwrap(); let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 }; let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 }; - let mut discovery1 = Discovery::new(&key1, ep1.clone(), 0); - let mut discovery2 = Discovery::new(&key2, ep2.clone(), 0); + let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0); + let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0); let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap(); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 806ef2b92..3d55430bd 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::net::{SocketAddr, SocketAddrV4}; +use std::net::{SocketAddr}; use std::collections::{HashMap}; use std::hash::{Hasher}; use std::str::{FromStr}; @@ -39,8 +39,8 @@ use network::{NetworkProtocolHandler, PROTOCOL_VERSION}; use network::node_table::*; use network::stats::NetworkStats; use network::error::DisconnectReason; -use igd::{PortMappingProtocol, search_gateway}; use network::discovery::{Discovery, TableUpdates, NodeEntry}; +use network::ip_utils::{map_external_address, select_public_address}; type Slab = ::slab::Slab; @@ -55,10 +55,12 @@ const MAINTENANCE_TIMEOUT: u64 = 1000; pub struct NetworkConfiguration { /// Directory path to store network configuration. None means nothing will be saved pub config_path: Option, - /// IP address to listen for incoming connections - pub listen_address: SocketAddr, - /// IP address to advertise - pub public_address: SocketAddr, + /// IP address to listen for incoming connections. Listen to all connections by default + pub listen_address: Option, + /// IP address to advertise. Detected automatically if none. + pub public_address: Option, + /// Port for UDP connections, same as TCP by default + pub udp_port: Option, /// Enable NAT configuration pub nat_enabled: bool, /// Enable discovery @@ -78,8 +80,9 @@ impl NetworkConfiguration { pub fn new() -> NetworkConfiguration { NetworkConfiguration { config_path: None, - listen_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), - public_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), + listen_address: None, + public_address: None, + udp_port: None, nat_enabled: true, discovery_enabled: true, pin: false, @@ -92,48 +95,9 @@ impl NetworkConfiguration { /// Create new default configuration with sepcified listen port. pub fn new_with_port(port: u16) -> NetworkConfiguration { let mut config = NetworkConfiguration::new(); - config.listen_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap(); - config.public_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap(); + config.listen_address = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap()); config } - - /// Conduct NAT if needed. - pub fn prepared(self) -> Self { - let mut listen = self.listen_address; - let mut public = self.public_address; - - if self.nat_enabled { - info!("Enabling NAT..."); - match search_gateway() { - Err(ref err) => warn!("Port mapping error: {}", err), - Ok(gateway) => { - let int_addr = SocketAddrV4::from_str("127.0.0.1:30304").unwrap(); - match gateway.get_any_address(PortMappingProtocol::TCP, int_addr, 0, "Parity Node/TCP") { - Err(ref err) => { - warn!("Port mapping error: {}", err); - }, - Ok(ext_addr) => { - info!("Local gateway: {}, External ip address: {}", gateway, ext_addr); - public = SocketAddr::V4(ext_addr); - listen = SocketAddr::V4(int_addr); - }, - } - }, - } - } - - NetworkConfiguration { - config_path: self.config_path, - listen_address: listen, - public_address: public, - nat_enabled: false, - discovery_enabled: self.discovery_enabled, - pin: self.pin, - boot_nodes: self.boot_nodes, - use_secret: self.use_secret, - ideal_peers: self.ideal_peers, - } - } } // Tokens @@ -333,16 +297,39 @@ pub struct Host where Message: Send + Sync + Clone { timers: RwLock>, timer_counter: RwLock, stats: Arc, + public_endpoint: NodeEndpoint, } impl Host where Message: Send + Sync + Clone { /// Create a new instance pub fn new(config: NetworkConfiguration) -> Host { - let config = config.prepared(); + let listen_address = match config.listen_address { + None => SocketAddr::from_str("0.0.0.0:30304").unwrap(), + Some(addr) => addr, + }; + + let udp_port = config.udp_port.unwrap_or(listen_address.port()); + let public_endpoint = match config.public_address { + None => { + let public_address = select_public_address(listen_address.port()); + let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; + if config.nat_enabled { + match map_external_address(&local_endpoint) { + Some(endpoint) => { + info!("NAT Mappped to external address {}", endpoint.address); + endpoint + }, + None => local_endpoint + } + } else { + local_endpoint + } + } + Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port } + }; - let addr = config.listen_address; // Setup the server socket - let tcp_listener = TcpListener::bind(&addr).unwrap(); + let tcp_listener = TcpListener::bind(&listen_address).unwrap(); let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { @@ -356,8 +343,7 @@ impl Host where Message: Send + Sync + Clone { }, |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; - let endpoint = NodeEndpoint { address: config.public_address.clone(), udp_port: addr.port() }; - let discovery = Discovery::new(&keys, endpoint, DISCOVERY); + let discovery = Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY); let path = config.config_path.clone(); let mut host = Host:: { info: RwLock::new(HostInfo { @@ -378,8 +364,9 @@ impl Host where Message: Send + Sync + Clone { timers: RwLock::new(HashMap::new()), timer_counter: RwLock::new(USER_TIMER), stats: Arc::new(NetworkStats::default()), + public_endpoint: public_endpoint, }; - let port = host.info.read().unwrap().config.listen_address.port(); + let port = listen_address.port(); host.info.write().unwrap().deref_mut().listen_port = port; let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); @@ -409,8 +396,8 @@ impl Host where Message: Send + Sync + Clone { self.info.read().unwrap().client_version.clone() } - pub fn client_id(&self) -> NodeId { - self.info.read().unwrap().id().clone() + pub fn client_url(&self) -> String { + format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.public_endpoint.clone())) } fn maintain_network(&self, io: &IoContext>) { @@ -456,13 +443,15 @@ impl Host where Message: Send + Sync + Clone { } let handshake_count = self.handshake_count(); - if handshake_count >= MAX_HANDSHAKES { + // allow 16 slots for incoming connections + let handshake_limit = MAX_HANDSHAKES - 16; + if handshake_count >= handshake_limit { return; } let nodes = { self.nodes.read().unwrap().nodes() }; for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)) - .take(min(MAX_HANDSHAKES_PER_ROUND, MAX_HANDSHAKES - handshake_count)) { + .take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) { self.connect_peer(&id, io); } debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index c5066ff99..ff52212af 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -73,6 +73,7 @@ mod service; mod error; mod node_table; mod stats; +mod ip_utils; #[cfg(test)] mod tests; diff --git a/util/src/network/service.rs b/util/src/network/service.rs index 60f0ec415..1cd48abe1 100644 --- a/util/src/network/service.rs +++ b/util/src/network/service.rs @@ -42,7 +42,7 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat let host = Arc::new(Host::new(config)); let stats = host.stats().clone(); let host_info = host.client_version(); - info!("Host ID={:?}", host.client_id()); + info!("Node URL: {}", host.client_url()); try!(io_service.register_handler(host)); Ok(NetworkService { io_service: io_service, From f771306867121d4dbe30c289305994dba50c9fed Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 02:05:45 +0100 Subject: [PATCH 037/753] Get public address/UPNP refactoring --- util/src/network/ip_utils.rs | 176 +++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 util/src/network/ip_utils.rs diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs new file mode 100644 index 000000000..8f94073b3 --- /dev/null +++ b/util/src/network/ip_utils.rs @@ -0,0 +1,176 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +// Based on original work by David Levy https://raw.githubusercontent.com/dlevy47/rust-interfaces + +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::io; +use igd::{PortMappingProtocol, search_gateway_from_timeout}; +use std::time::Duration; +use network::node_table::{NodeEndpoint}; + +pub enum IpAddr{ + V4(Ipv4Addr), + V6(Ipv6Addr), +} + +#[cfg(not(windows))] +mod getinterfaces { + use std::{mem, io, ptr}; + use libc::{AF_INET, AF_INET6}; + use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6}; + use std::net::{Ipv4Addr, Ipv6Addr}; + use super::IpAddr; + + fn convert_sockaddr (sa: *mut sockaddr) -> Option { + if sa == ptr::null_mut() { return None; } + + let (addr, _) = match unsafe { *sa }.sa_family as i32 { + AF_INET => { + let sa: *const sockaddr_in = unsafe { mem::transmute(sa) }; + let sa = & unsafe { *sa }; + let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port); + ( + IpAddr::V4(Ipv4Addr::new( + (addr & 0x000000FF) as u8, + ((addr & 0x0000FF00) >> 8) as u8, + ((addr & 0x00FF0000) >> 16) as u8, + ((addr & 0xFF000000) >> 24) as u8, + )), + port + ) + }, + AF_INET6 => { + let sa: *const sockaddr_in6 = unsafe { mem::transmute(sa) }; + let sa = & unsafe { *sa }; + let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port); + let addr: [u16; 8] = unsafe { mem::transmute(addr) }; + ( + IpAddr::V6(Ipv6Addr::new( + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5], + addr[6], + addr[7], + )), + port + ) + }, + _ => return None, + }; + Some(addr) + } + + fn convert_ifaddrs (ifa: *mut ifaddrs) -> Option { + let ifa = unsafe { &mut *ifa }; + convert_sockaddr(ifa.ifa_addr) + } + + pub fn get_all() -> io::Result> { + let mut ifap: *mut ifaddrs = unsafe { mem::zeroed() }; + if unsafe { getifaddrs(&mut ifap as *mut _) } != 0 { + return Err(io::Error::last_os_error()); + } + + let mut ret = Vec::new(); + let mut cur: *mut ifaddrs = ifap; + while cur != ptr::null_mut() { + if let Some(ip_addr) = convert_ifaddrs(cur) { + ret.push(ip_addr); + } + + //TODO: do something else maybe? + cur = unsafe { (*cur).ifa_next }; + } + + unsafe { freeifaddrs(ifap) }; + Ok(ret) + } +} + +#[cfg(not(windows))] +fn get_if_addrs() -> io::Result> { + getinterfaces::get_all() +} + +#[cfg(windows)] +fn get_if_addrs() -> io::Result> { + Ok(Vec::new()) +} + +/// Select the best available public address +pub fn select_public_address(port: u16) -> SocketAddr { + match get_if_addrs() { + Ok(list) => { + //prefer IPV4 bindings + for addr in &list { //TODO: use better criteria than just the first in the list + match *addr { + IpAddr::V4(a) if !a.is_unspecified() && !a.is_loopback() && !a.is_link_local() => { + return SocketAddr::V4(SocketAddrV4::new(a, port)); + }, + _ => {}, + } + } + for addr in list { + match addr { + IpAddr::V6(a) if !a.is_unspecified() && !a.is_loopback() => { + return SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)); + }, + _ => {}, + } + } + }, + Err(e) => debug!("Error listing public interfaces: {:?}", e) + } + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) +} + +pub fn map_external_address(local: &NodeEndpoint) -> Option { + if let SocketAddr::V4(ref local_addr) = local.address { + match search_gateway_from_timeout(local_addr.ip().clone(), Duration::new(5, 0)) { + Err(ref err) => debug!("Gateway search error: {}", err), + Ok(gateway) => { + match gateway.get_external_ip() { + Err(ref err) => { + debug!("IP request error: {}", err); + }, + Ok(external_addr) => { + match gateway.add_any_port(PortMappingProtocol::TCP, SocketAddrV4::new(local_addr.ip().clone(), local_addr.port()), 0, "Parity Node/TCP") { + Err(ref err) => { + debug!("Port mapping error: {}", err); + }, + Ok(tcp_port) => { + match gateway.add_any_port(PortMappingProtocol::UDP, SocketAddrV4::new(local_addr.ip().clone(), local.udp_port), 0, "Parity Node/UDP") { + Err(ref err) => { + debug!("Port mapping error: {}", err); + }, + Ok(udp_port) => { + return Some(NodeEndpoint { address: SocketAddr::V4(SocketAddrV4::new(external_addr, tcp_port)), udp_port: udp_port }); + }, + } + }, + } + }, + } + }, + } + } + None +} + From 58fdfe77d3c93a2599805bd718401f7ebedba645 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 02:31:17 +0100 Subject: [PATCH 038/753] Handle pinning and enable_discovery options --- util/src/network/host.rs | 44 ++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 3d55430bd..004410466 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -291,13 +291,14 @@ pub struct Host where Message: Send + Sync + Clone { tcp_listener: Mutex, handshakes: Arc>>, sessions: Arc>>, - discovery: Mutex, + discovery: Option>, nodes: RwLock, handlers: RwLock>>>, timers: RwLock>, timer_counter: RwLock, stats: Arc, public_endpoint: NodeEndpoint, + pinned_nodes: Vec, } impl Host where Message: Send + Sync + Clone { @@ -343,7 +344,9 @@ impl Host where Message: Send + Sync + Clone { }, |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; - let discovery = Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY); + let discovery = if config.discovery_enabled && !config.pin { + Some(Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY)) + } else { None }; let path = config.config_path.clone(); let mut host = Host:: { info: RwLock::new(HostInfo { @@ -355,7 +358,7 @@ impl Host where Message: Send + Sync + Clone { listen_port: 0, capabilities: Vec::new(), }), - discovery: Mutex::new(discovery), + discovery: discovery.map(Mutex::new), tcp_listener: Mutex::new(tcp_listener), handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), @@ -365,6 +368,7 @@ impl Host where Message: Send + Sync + Clone { timer_counter: RwLock::new(USER_TIMER), stats: Arc::new(NetworkStats::default()), public_endpoint: public_endpoint, + pinned_nodes: Vec::new(), }; let port = listen_address.port(); host.info.write().unwrap().deref_mut().listen_port = port; @@ -373,7 +377,9 @@ impl Host where Message: Send + Sync + Clone { for n in boot_nodes { host.add_node(&n); } - host.discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries()); + if let Some(ref mut discovery) = host.discovery { + discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries()); + } host } @@ -386,8 +392,11 @@ impl Host where Message: Send + Sync + Clone { Err(e) => { warn!("Could not add node: {:?}", e); }, Ok(n) => { let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; + self.pinned_nodes.push(n.id.clone()); self.nodes.write().unwrap().add_node(n); - self.discovery.lock().unwrap().add_node(entry); + if let Some(ref mut discovery) = self.discovery { + discovery.lock().unwrap().add_node(entry); + } } } } @@ -437,6 +446,7 @@ impl Host where Message: Send + Sync + Clone { fn connect_peers(&self, io: &IoContext>) { let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; + let pin = { self.info.read().unwrap().deref().config.pin }; let session_count = self.session_count(); if session_count >= ideal_peers as usize { return; @@ -449,7 +459,7 @@ impl Host where Message: Send + Sync + Clone { return; } - let nodes = { self.nodes.read().unwrap().nodes() }; + let nodes = if pin { self.pinned_nodes.clone() } else { self.nodes.read().unwrap().nodes() }; for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)) .take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) { self.connect_peer(&id, io); @@ -670,7 +680,9 @@ impl Host where Message: Send + Sync + Clone { if let Ok(address) = session.remote_addr() { let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); - self.discovery.lock().unwrap().add_node(entry); + if let Some(ref discovery) = self.discovery { + discovery.lock().unwrap().add_node(entry); + } } } Arc::new(Mutex::new(session)) @@ -759,8 +771,10 @@ impl IoHandler> for Host where Messa io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); io.register_stream(DISCOVERY).expect("Error registering UDP listener"); io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer"); - io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); - io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); + if self.discovery.is_some() { + io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); + io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); + } } fn stream_hup(&self, io: &IoContext>, stream: StreamToken) { @@ -777,7 +791,7 @@ impl IoHandler> for Host where Messa FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), DISCOVERY => { - if let Some(node_changes) = self.discovery.lock().unwrap().readable() { + if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().readable() { self.update_nodes(io, node_changes); } io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); @@ -792,7 +806,7 @@ impl IoHandler> for Host where Messa FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io), DISCOVERY => { - self.discovery.lock().unwrap().writable(); + self.discovery.as_ref().unwrap().lock().unwrap().writable(); io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); } _ => panic!("Received unknown writable token"), @@ -805,11 +819,11 @@ impl IoHandler> for Host where Messa FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { - self.discovery.lock().unwrap().refresh(); + self.discovery.as_ref().unwrap().lock().unwrap().refresh(); io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); }, DISCOVERY_ROUND => { - if let Some(node_changes) = self.discovery.lock().unwrap().round() { + if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().round() { self.update_nodes(io, node_changes); } io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); @@ -880,7 +894,7 @@ impl IoHandler> for Host where Messa connection.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); } } - DISCOVERY => self.discovery.lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), + DISCOVERY => self.discovery.as_ref().unwrap().lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } @@ -922,7 +936,7 @@ impl IoHandler> for Host where Messa connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); } } - DISCOVERY => self.discovery.lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), + DISCOVERY => self.discovery.as_ref().unwrap().lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } From 33e8d749d2da4bc56213d4348bd163bccfea3c88 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 03:05:05 +0100 Subject: [PATCH 039/753] Max handhsakes reached is now a debug warning --- util/src/network/host.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 004410466..24f24fc6f 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -513,7 +513,7 @@ impl Host where Message: Send + Sync + Clone { }); Arc::new(Mutex::new(handshake)) }).is_none() { - warn!("Max handshakes reached"); + debug!("Max handshakes reached"); } } From 26e992ad2ed4381762f15c3544b63eae951d40b8 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 16 Feb 2016 11:30:22 +0300 Subject: [PATCH 040/753] encrypting any bytes covertible now via hashmap --- util/src/bytes.rs | 4 +++ util/src/keys/directory.rs | 26 +++++++------- util/src/keys/encryptor.rs | 74 +++++++++++++++++++++++++++++++++----- 3 files changed, 82 insertions(+), 22 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 5ad2660e8..0006827e8 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -178,6 +178,10 @@ impl BytesConvertable for Vec { fn bytes(&self) -> &[u8] { self } } +impl BytesConvertable for String { + fn bytes(&self) -> &[u8] { &self.as_bytes() } +} + macro_rules! impl_bytes_convertable_for_array { ($zero: expr) => (); ($len: expr, $($idx: expr),*) => { diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 23e82d010..ccd7d8fb4 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -27,7 +27,7 @@ const MAX_CACHE_USAGE_TRACK: usize = 128; #[derive(PartialEq, Debug, Clone)] pub enum CryptoCipherType { /// aes-128-ctr with 128-bit initialisation vector(iv) - Aes128Ctr(U128) + Aes128Ctr(H128) } #[derive(PartialEq, Debug, Clone)] @@ -182,7 +182,7 @@ impl KeyFileCrypto { Some("aes-128-ctr") => CryptoCipherType::Aes128Ctr( match try!(as_object.get("cipherparams").ok_or(CryptoParseError::NoCipherParameters)).as_object() { None => { return Err(CryptoParseError::NoCipherParameters); }, - Some(cipher_param) => match U128::from_str(match cipher_param["iv"].as_string() { + Some(cipher_param) => match H128::from_str(match cipher_param["iv"].as_string() { None => { return Err(CryptoParseError::NoInitialVector); }, Some(iv_hex_string) => iv_hex_string }) @@ -231,7 +231,7 @@ impl KeyFileCrypto { fn to_json(&self) -> Json { let mut map = BTreeMap::new(); match self.cipher_type { - CryptoCipherType::Aes128Ctr(iv) => { + CryptoCipherType::Aes128Ctr(ref iv) => { map.insert("cipher".to_owned(), Json::String("aes-128-ctr".to_owned())); let mut cipher_params = BTreeMap::new(); cipher_params.insert("iv".to_owned(), Json::String(format!("{:?}", iv))); @@ -260,7 +260,7 @@ impl KeyFileCrypto { /// `c` - number of iterations for derived key. /// `salt` - cryptographic site, random 256-bit hash (ensure it's crypto-random). /// `iv` - initialisation vector. - pub fn new_pbkdf2(cipher_text: Bytes, iv: U128, salt: H256, c: u32, dk_len: u32) -> KeyFileCrypto { + pub fn new_pbkdf2(cipher_text: Bytes, iv: H128, salt: H256, c: u32, dk_len: u32) -> KeyFileCrypto { KeyFileCrypto { cipher_type: CryptoCipherType::Aes128Ctr(iv), cipher_text: cipher_text, @@ -331,7 +331,7 @@ enum CryptoParseError { InvalidCipherType(Mismatch), NoInitialVector, NoCipherParameters, - InvalidInitialVector(FromHexError), + InvalidInitialVector(UtilError), NoKdf, NoKdfType, Scrypt(ScryptParseError), @@ -832,14 +832,14 @@ mod file_tests { #[test] fn can_create_key_with_new_id() { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32)); assert!(!uuid_to_string(&key.id).is_empty()); } #[test] fn can_load_json_from_itself() { let cipher_text: Bytes = FromHex::from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaa22222222222222222222222").unwrap(); - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32)); let json = key.to_json(); let loaded_key = KeyFileContent::from_json(&json).unwrap(); @@ -997,7 +997,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32))).unwrap(); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32))).unwrap(); let path = directory.key_path(&uuid); let key = KeyDirectory::load_key(&path).unwrap(); @@ -1013,7 +1013,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..1000 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } @@ -1033,7 +1033,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..1000 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } @@ -1066,7 +1066,7 @@ mod specs { let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32))); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32))); assert!(uuid.is_ok()); } @@ -1076,7 +1076,7 @@ mod specs { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32))).unwrap(); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32))).unwrap(); let key = directory.get(&uuid).unwrap(); @@ -1091,7 +1091,7 @@ mod specs { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..10 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } diff --git a/util/src/keys/encryptor.rs b/util/src/keys/encryptor.rs index cbc926dc6..7645a2b84 100644 --- a/util/src/keys/encryptor.rs +++ b/util/src/keys/encryptor.rs @@ -18,17 +18,25 @@ use keys::directory::*; use common::*; +use rcrypto::pbkdf2::*; +use rcrypto::aes; +use rcrypto::hmac::*; +use crypto; + +const KEY_LENGTH: u32 = 32; +const KEY_ITERATIONS: u32 = 4096; +const KEY_LENGTH_AES: u32 = KEY_LENGTH/2; pub trait EncryptedHashMap { // Returns existing value for the key, if any - fn get(&self, key: &Key, password: &str) -> Option; + fn get(&self, key: &Key, password: &str) -> Option; // Insert new encrypted key-value and returns previous if there was any - fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; + fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; // Removes key-value by key and returns the removed one, if any exists and password was provided - fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; + fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; // Deletes key-value by key and returns if the key-value existed fn delete(&mut self, key: &Key) -> bool { - self.remove::<()>(key, None).is_some() + self.remove::<&[u8]>(key, None).is_some() } } @@ -36,8 +44,25 @@ pub struct SecretStore { directory: KeyDirectory } +impl SecretStore { + fn new() -> SecretStore { + let mut path = ::std::env::home_dir().expect("Failed to get home dir"); + path.push(".keys"); + SecretStore { + directory: KeyDirectory::new(&path) + } + } + + #[cfg(test)] + fn new_test(path: &::tests::helpers::RandomTempPath) -> SecretStore { + SecretStore { + directory: KeyDirectory::new(path.as_path()) + } + } +} + impl EncryptedHashMap for SecretStore { - fn get(&self, key: &H128, password: &str) -> Option { + fn get(&self, key: &H128, password: &str) -> Option { match self.directory.get(key) { Some(key_file) => { let mut instance = Value::default(); @@ -49,17 +74,48 @@ impl EncryptedHashMap for SecretStore { } - fn insert(&mut self, key: H128, value: Value, password: &str) -> Option{ - let previous = if let Some(key_file) = self.directory.get(&key) { self.get(&key, password) } else { None }; + fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { + let previous = if let Some(_) = self.directory.get(&key) { self.get(&key, password) } else { None }; + + let salt = H256::random(); + let iv = H128::random(); + let mut key_file = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(vec![], iv.clone(), salt.clone(), KEY_ITERATIONS, KEY_LENGTH)); + + let mut mac = Hmac::new(::rcrypto::sha2::Sha256::new(), password.as_bytes()); + let mut derived_key = vec![0u8; KEY_LENGTH as usize]; + pbkdf2(&mut mac, &salt.as_slice(), KEY_ITERATIONS, &mut derived_key); + let key = &derived_key[KEY_LENGTH_AES as usize..KEY_LENGTH as usize]; + + let mut cipher_text = vec![0u8; value.as_slice().len()]; + crypto::aes::encrypt(&key, &iv.as_slice(), &value.as_slice(), &mut cipher_text); + key_file.crypto.cipher_text = cipher_text; + previous } - fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { + fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { let previous = match (self.directory.get(&key), password) { - (Some(key_file), Some(pass)) => self.get(&key, pass), + (Some(_), Some(pass)) => self.get(&key, pass), (_, _) => None }; previous } } + + +#[cfg(test)] +mod tests { + use super::*; + use tests::helpers::*; + use common::*; + + #[test] + fn secret_store_insert() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + + sstore.insert(H128::random(), "Cat".to_owned(), "pass"); + } + +} From 425350aa65efd8a31685a02525d82eb9cced8381 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 16 Feb 2016 10:53:28 +0100 Subject: [PATCH 041/753] Add Morden bootnode. --- ethcore/res/ethereum/morden.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 0d0c2489d..2e45c2edd 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -25,6 +25,9 @@ "extraData": "0x", "gasLimit": "0x2fefd8" }, + "nodes": [ + "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" + ], "accounts": { "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, From 714f01fda737b24f2be3ff20837899c7f0a213f5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 16 Feb 2016 11:00:38 +0100 Subject: [PATCH 042/753] Remove contributing stuff now that we have CLA bot. --- CONTRIBUTING.md | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index f679363b8..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,12 +0,0 @@ -# Contributing to Parity - -## License - -By contributing to Parity, you agree that your contributions will be -licensed under the [BSD License](LICENSE). - -At the top of every source code file you alter, after the initial -licence section, please append a second section that reads: - -Portions contributed by YOUR NAME are hereby placed under the BSD licence. - From b7c5b0a3c13a621168588406f497c8621aec16b6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 16 Feb 2016 13:12:29 +0300 Subject: [PATCH 043/753] script for full test suite --- test.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 test.sh diff --git a/test.sh b/test.sh new file mode 100644 index 000000000..60ebf1d3a --- /dev/null +++ b/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# Running Parity Full Test Sute + +cargo test --features ethcore/json-tests $1 -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --no-run || exit $? From feb9b96ce7cdb9ee51c0b1db4b625664e8724ca5 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 16 Feb 2016 13:40:58 +0300 Subject: [PATCH 044/753] version bump, test script for full suite --- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 2 +- ethash/Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- evmjit/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- test.sh | 2 +- util/Cargo.toml | 2 +- 9 files changed, 25 insertions(+), 25 deletions(-) mode change 100644 => 100755 test.sh diff --git a/Cargo.lock b/Cargo.lock index 1fa63e621..1e9f57900 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,16 +1,16 @@ [root] name = "parity" -version = "0.9.0" +version = "0.9.99" dependencies = [ "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.0.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "docopt_macros 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.0", - "ethcore-rpc 0.9.0", - "ethcore-util 0.9.0", - "ethsync 0.1.0", + "ethcore 0.9.99", + "ethcore-rpc 0.9.99", + "ethcore-util 0.9.99", + "ethsync 0.9.99", "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -156,7 +156,7 @@ dependencies = [ [[package]] name = "ethash" -version = "0.1.0" +version = "0.9.99" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -165,13 +165,13 @@ dependencies = [ [[package]] name = "ethcore" -version = "0.9.0" +version = "0.9.99" dependencies = [ "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 0.1.0", - "ethcore-util 0.9.0", + "ethash 0.9.99", + "ethcore-util 0.9.99", "heapsize 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -184,12 +184,12 @@ dependencies = [ [[package]] name = "ethcore-rpc" -version = "0.9.0" +version = "0.9.99" dependencies = [ "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.0", - "ethcore-util 0.9.0", - "ethsync 0.1.0", + "ethcore 0.9.99", + "ethcore-util 0.9.99", + "ethsync 0.9.99", "jsonrpc-core 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "ethcore-util" -version = "0.9.0" +version = "0.9.99" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -230,12 +230,12 @@ dependencies = [ [[package]] name = "ethsync" -version = "0.1.0" +version = "0.9.99" dependencies = [ "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.0", - "ethcore-util 0.9.0", + "ethcore 0.9.99", + "ethcore-util 0.9.99", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index ca2ad9c6c..c58cacf0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore client." name = "parity" -version = "0.9.0" +version = "0.9.99" license = "GPL-3.0" authors = ["Ethcore "] diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 4c0b3d65e..4bba71a14 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ethash" -version = "0.1.0" +version = "0.9.99" authors = ["arkpar "] [dependencies] diff --git a/evmjit/Cargo.toml b/evmjit/Cargo.toml index ccd9cc718..9449af82d 100644 --- a/evmjit/Cargo.toml +++ b/evmjit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evmjit" -version = "0.9.0" +version = "0.9.99" authors = ["debris "] [lib] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 0bb255d98..b1af0a2fa 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore jsonrpc" name = "ethcore-rpc" -version = "0.9.0" +version = "0.9.99" license = "GPL-3.0" authors = ["Ethcore "] [dependencies] From 0699cdd5d02d07e0eba76aec9d2b7fb96e6bd980 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 16 Feb 2016 11:41:34 +0100 Subject: [PATCH 045/753] tests for blockchain bloomfilters --- ethcore/src/blockchain.rs | 16 ++++++++++++++++ ethcore/src/chainfilter/chainfilter.rs | 4 ++-- ethcore/src/extras.rs | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 68d677703..28a401e55 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -941,4 +941,20 @@ mod tests { assert_eq!(bc.transaction(&bc.transaction_address(&t.hash()).unwrap()).unwrap(), t); } } + + #[test] + fn test_bloom_filter_simple() { + let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); + + // bloom filter flow block 300054 + let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); + + let bloom = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(&genesis, temp.as_path()); + bc.insert_block(&b1, &[]); + let blocks = bc.blocks_with_bloom(&bloom, 0, 2); + assert_eq!(blocks, vec![1]); + } } diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs index ab27f77ff..4f7f30928 100644 --- a/ethcore/src/chainfilter/chainfilter.rs +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -90,9 +90,9 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource // if we are on the lowest level 0 => return match offset < to_block { // take the value if its smaller than to_block - true => Some(vec![offset]), + true if level_bloom.contains(bloom) => Some(vec![offset]), // return None if it is is equal to to_block - false => None + _ => None }, // return None if current level doesnt contain given bloom _ if !level_bloom.contains(bloom) => return None, diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index 305b7767e..1ad4c8e7b 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -261,6 +261,7 @@ impl Encodable for BlocksBlooms { } /// Represents location of bloom in database. +#[derive(Debug)] pub struct BlocksBloomLocation { /// Unique hash of BlocksBloom pub hash: H256, From d000ad2441126893d1d14c97ccf60fb90a7ef3a8 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 16 Feb 2016 14:46:21 +0100 Subject: [PATCH 046/753] more tests and fixes for blockchains bloom filters --- ethcore/src/blockchain.rs | 183 +++++++++++++++++++++++++++++--------- ethcore/src/extras.rs | 2 +- 2 files changed, 141 insertions(+), 44 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 28a401e55..91c803b1f 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -53,6 +53,60 @@ pub struct CacheSize { pub blocks_blooms: usize } +struct BloomIndexer { + index_size: usize, + levels: u8 +} + +impl BloomIndexer { + fn new(index_size: usize, levels: u8) -> Self { + BloomIndexer { + index_size: index_size, + levels: levels + } + } + + /// Calculates bloom's position in database. + fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { + use std::{mem, ptr}; + + let hash = unsafe { + let mut hash: H256 = mem::zeroed(); + ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); + hash[8] = bloom_index.level; + hash.reverse(); + hash + }; + + BlocksBloomLocation { + hash: hash, + index: bloom_index.index % self.index_size + } + } + + fn index_size(&self) -> usize { + self.index_size + } + + fn levels(&self) -> u8 { + self.levels + } +} + +/// Blockchain update info. +struct ExtrasUpdate { + /// Block hash. + hash: H256, + /// DB update batch. + batch: WriteBatch, + /// Inserted block familial details. + details: BlockDetails, + /// New best block (if it has changed). + new_best: Option, + /// Changed blocks bloom location hashes. + bloom_hashes: HashSet +} + impl CacheSize { /// Total amount used by the cache. fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms } @@ -175,14 +229,13 @@ pub struct BlockChain { cache_man: RwLock, - // blooms config - bloom_index_size: usize, - bloom_levels: u8 + // blooms indexing + bloom_indexer: BloomIndexer } impl FilterDataSource for BlockChain { fn bloom_at_index(&self, bloom_index: &BloomIndex) -> Option { - let location = self.blocks_bloom_location(bloom_index); + let location = self.bloom_indexer.location(bloom_index); self.blocks_blooms(&location.hash).and_then(|blooms| blooms.blooms.into_iter().nth(location.index).cloned()) } } @@ -236,7 +289,7 @@ impl BlockProvider for BlockChain { /// Returns numbers of blocks containing given bloom. fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { - let filter = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels); + let filter = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()); filter.blocks_with_bloom(bloom, from_block as usize, to_block as usize).into_iter().map(|b| b as BlockNumber).collect() } } @@ -298,8 +351,7 @@ impl BlockChain { extras_db: extras_db, blocks_db: blocks_db, cache_man: RwLock::new(cache_man), - bloom_index_size: BLOOM_INDEX_SIZE, - bloom_levels: BLOOM_LEVELS + bloom_indexer: BloomIndexer::new(BLOOM_INDEX_SIZE, BLOOM_LEVELS) }; // load best block @@ -464,27 +516,38 @@ impl BlockChain { // store block in db self.blocks_db.put(&hash, &bytes).unwrap(); - let (batch, new_best, details) = self.block_to_extras_insert_batch(bytes, receipts); + let update = self.block_to_extras_update(bytes, receipts); + self.apply_update(update); + } + /// Applies extras update. + fn apply_update(&self, update: ExtrasUpdate) { // update best block let mut best_block = self.best_block.write().unwrap(); - if let Some(b) = new_best { + if let Some(b) = update.new_best { *best_block = b; } - // update caches - let mut write = self.block_details.write().unwrap(); - write.remove(&header.parent_hash()); - write.insert(hash.clone(), details); - self.note_used(CacheID::Block(hash)); + // update details cache + let mut write_details = self.block_details.write().unwrap(); + write_details.remove(&update.details.parent); + write_details.insert(update.hash.clone(), update.details); + self.note_used(CacheID::Block(update.hash)); + + // update blocks blooms cache + let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); + for bloom_hash in &update.bloom_hashes { + write_blocks_blooms.remove(bloom_hash); + } // update extras database - self.extras_db.write(batch).unwrap(); + self.extras_db.write(update.batch).unwrap(); } /// Transforms block into WriteBatch that may be written into database /// Additionally, if it's new best block it returns new best block object. - fn block_to_extras_insert_batch(&self, bytes: &[u8], _receipts: &[Receipt]) -> (WriteBatch, Option, BlockDetails) { + //fn block_to_extras_insert_batch(&self, bytes: &[u8], _receipts: &[Receipt]) -> (WriteBatch, Option, BlockDetails) { + fn block_to_extras_update(&self, bytes: &[u8], _receipts: &[Receipt]) -> ExtrasUpdate { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -522,8 +585,6 @@ impl BlockChain { }); } - - // save blooms (is it really required?). maybe store receipt whole instead? //let blooms: Vec = receipts.iter().map(|r| r.log_bloom.clone()).collect(); //batch.put_extras(&hash, &BlockLogBlooms { @@ -532,7 +593,13 @@ impl BlockChain { // if it's not new best block, just return if !is_new_best { - return (batch, None, details); + return ExtrasUpdate { + hash: hash.clone(), + batch: batch, + details: details, + new_best: None, + bloom_hashes: HashSet::new() + }; } // if its new best block we need to make sure that all ancestors @@ -550,7 +617,7 @@ impl BlockChain { batch.put_extras(&header.number(), &hash); // update block blooms - modified_blooms = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels) + modified_blooms = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) .add_bloom(&header.log_bloom(), header.number() as usize); }, // it is a fork @@ -569,7 +636,7 @@ impl BlockChain { .collect(); // reset blooms chain head - modified_blooms = ChainFilter::new(self, self.bloom_index_size, self.bloom_levels) + modified_blooms = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) .reset_chain_head(&blooms, start_number as usize, self.best_block_number() as usize); }, // route.blocks.len() could be 0 only if inserted block is best block, @@ -577,10 +644,14 @@ impl BlockChain { _ => { unreachable!(); } }; + let bloom_hashes = modified_blooms.iter() + .map(|(bloom_index, _)| self.bloom_indexer.location(&bloom_index).hash) + .collect(); + for (hash, blocks_blooms) in modified_blooms.into_iter() .fold(HashMap::new(), | mut acc, (bloom_index, bloom) | { { - let location = self.blocks_bloom_location(&bloom_index); + let location = self.bloom_indexer.location(&bloom_index); let mut blocks_blooms = acc.entry(location.hash).or_insert_with(BlocksBlooms::new); blocks_blooms.blooms[location.index] = bloom; } @@ -593,12 +664,18 @@ impl BlockChain { batch.put(b"best", &hash).unwrap(); let best_block = BestBlock { - hash: hash, + hash: hash.clone(), number: header.number(), total_difficulty: total_difficulty }; - (batch, Some(best_block), details) + ExtrasUpdate { + hash: hash, + batch: batch, + new_best: Some(best_block), + details: details, + bloom_hashes: bloom_hashes + } } /// Get best block hash. @@ -621,22 +698,7 @@ impl BlockChain { self.query_extras(hash, &self.blocks_blooms) } - /// Calculates bloom's position in database. - fn blocks_bloom_location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { - use std::{mem, ptr}; - - let hash = unsafe { - let mut hash: H256 = mem::zeroed(); - ptr::copy(&[bloom_index.index / self.bloom_index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); - hash[8] = bloom_index.level; - hash - }; - BlocksBloomLocation { - hash: hash, - index: bloom_index.index % self.bloom_index_size - } - } fn query_extras(&self, hash: &K, cache: &RwLock>) -> Option where T: Clone + Decodable + ExtrasIndexable, @@ -740,7 +802,7 @@ mod tests { use std::str::FromStr; use rustc_serialize::hex::FromHex; use util::hash::*; - use blockchain::*; + use blockchain::{BlockProvider, BlockChain}; use tests::helpers::*; #[test] @@ -946,15 +1008,50 @@ mod tests { fn test_bloom_filter_simple() { let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); + let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); + // bloom filter flow block 300054 - let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); + let b2 = "f902ccf901f9a0437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); let bloom = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); + let blocks = bc.blocks_with_bloom(&bloom, 0, 50); + assert_eq!(blocks, vec![]); + bc.insert_block(&b1, &[]); - let blocks = bc.blocks_with_bloom(&bloom, 0, 2); - assert_eq!(blocks, vec![1]); + assert_eq!(blocks, vec![]); + + bc.insert_block(&b2, &[]); + let blocks = bc.blocks_with_bloom(&bloom, 0, 50); + assert_eq!(blocks, vec![2]); + } + + #[test] + fn test_bloom_indexer() { + use chainfilter::BloomIndex; + use blockchain::BloomIndexer; + use extras::BlocksBloomLocation; + + let bi = BloomIndexer::new(16, 3); + + let index = BloomIndex::new(0, 0); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::new(), + index: 0 + }); + + let index = BloomIndex::new(1, 0); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::from_str("0000000000000000000000000000000000000000000000010000000000000000").unwrap(), + index: 0 + }); + + let index = BloomIndex::new(0, 299_999); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::from_str("000000000000000000000000000000000000000000000000000000000000493d").unwrap(), + index: 15 + }); } } diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index 1ad4c8e7b..66e734582 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -261,7 +261,7 @@ impl Encodable for BlocksBlooms { } /// Represents location of bloom in database. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct BlocksBloomLocation { /// Unique hash of BlocksBloom pub hash: H256, From 7e5e56de404af46d518ae2be4cf9a931c874ec34 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 16 Feb 2016 16:54:58 +0100 Subject: [PATCH 047/753] bloom_filters finally working --- ethcore/src/blockchain.rs | 41 +++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 91c803b1f..1a329610c 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -554,7 +554,7 @@ impl BlockChain { // prepare variables let hash = block.sha3(); - let mut parent_details = self.block_details(&header.parent_hash()).expect("Invalid parent hash."); + let mut parent_details = self.block_details(&header.parent_hash()).expect(format!("Invalid parent hash: {:?}", header.parent_hash()).as_ref()); let total_difficulty = parent_details.total_difficulty + header.difficulty(); let is_new_best = total_difficulty > self.best_block_total_difficulty(); let parent_hash = header.parent_hash(); @@ -648,16 +648,18 @@ impl BlockChain { .map(|(bloom_index, _)| self.bloom_indexer.location(&bloom_index).hash) .collect(); - for (hash, blocks_blooms) in modified_blooms.into_iter() + for (bloom_hash, blocks_blooms) in modified_blooms.into_iter() .fold(HashMap::new(), | mut acc, (bloom_index, bloom) | { { let location = self.bloom_indexer.location(&bloom_index); - let mut blocks_blooms = acc.entry(location.hash).or_insert_with(BlocksBlooms::new); + let mut blocks_blooms = acc + .entry(location.hash.clone()) + .or_insert_with(|| self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new)); blocks_blooms.blooms[location.index] = bloom; } acc }) { - batch.put_extras(&hash, &blocks_blooms); + batch.put_extras(&bloom_hash, &blocks_blooms); } // this is new best block @@ -698,8 +700,6 @@ impl BlockChain { self.query_extras(hash, &self.blocks_blooms) } - - fn query_extras(&self, hash: &K, cache: &RwLock>) -> Option where T: Clone + Decodable + ExtrasIndexable, K: ExtrasSliceConvertable + Eq + Hash + Clone { @@ -1008,24 +1008,35 @@ mod tests { fn test_bloom_filter_simple() { let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); - let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); + // bloom filter from block 300059 + let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000200000000000000000000000000000000000000000020000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080004000000000000000000000020008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); - // bloom filter flow block 300054 - let b2 = "f902ccf901f9a0437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); + // bloom filter from block 300054 + let b2 = "f902ccf901f9a04ef46c05763fffc5f7e59f92a7ef438ffccbb578e6e5d0f04e3df8a7fa6c02f6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - let bloom = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap(); + + let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); - let blocks = bc.blocks_with_bloom(&bloom, 0, 50); - assert_eq!(blocks, vec![]); + + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + assert_eq!(blocks_b1, vec![]); + assert_eq!(blocks_b2, vec![]); bc.insert_block(&b1, &[]); - assert_eq!(blocks, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![]); bc.insert_block(&b2, &[]); - let blocks = bc.blocks_with_bloom(&bloom, 0, 50); - assert_eq!(blocks, vec![2]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![2]); } #[test] From a649d6f1311b75e8328e840537502fdd4dc73c61 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 16 Feb 2016 19:19:32 +0300 Subject: [PATCH 048/753] first vector up --- util/src/keys/directory.rs | 21 +++++++- util/src/keys/mod.rs | 2 +- util/src/keys/{encryptor.rs => store.rs} | 61 +++++++++++++++++++++--- 3 files changed, 75 insertions(+), 9 deletions(-) rename util/src/keys/{encryptor.rs => store.rs} (60%) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index ccd7d8fb4..641a5cae4 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -168,6 +168,8 @@ pub struct KeyFileCrypto { pub cipher_text: Bytes, /// Password derived key generator function settings. pub kdf: KeyFileKdf, + /// Mac + pub mac: H256 } impl KeyFileCrypto { @@ -216,15 +218,24 @@ impl KeyFileCrypto { } }; - let cipher_text = match as_object["ciphertext"].as_string() { - None => { return Err(CryptoParseError::NoCipherText); } + let cipher_text = match try!(as_object.get("ciphertext").ok_or(CryptoParseError::NoCipherText)).as_string() { + None => { return Err(CryptoParseError::InvalidCipherText); } Some(text) => text }; + let mac: H256 = match try!(as_object.get("mac").ok_or(CryptoParseError::NoMac)).as_string() { + None => { return Err(CryptoParseError::InvalidMacFormat(None)) }, + Some(salt_value) => match H256::from_str(salt_value) { + Ok(salt_hex_value) => salt_hex_value, + Err(from_hex_error) => { return Err(CryptoParseError::InvalidMacFormat(Some(from_hex_error))); }, + } + }; + Ok(KeyFileCrypto { cipher_text: Bytes::from(cipher_text), cipher_type: cipher_type, kdf: kdf, + mac: mac, }) } @@ -251,6 +262,8 @@ impl KeyFileCrypto { KeyFileKdf::Scrypt(ref scrypt_params) => scrypt_params.to_json() }); + map.insert("mac".to_owned(), Json::String(format!("{:?}", self.mac))); + Json::Object(map) } @@ -270,6 +283,7 @@ impl KeyFileCrypto { c: c, prf: Pbkdf2CryptoFunction::HMacSha256 }), + mac: H256::random(), } } } @@ -324,7 +338,10 @@ pub struct KeyFileContent { #[derive(Debug)] enum CryptoParseError { + InvalidMacFormat(Option), + NoMac, NoCipherText, + InvalidCipherText, NoCipherType, InvalidJsonFormat, InvalidKdfType(Mismatch), diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index f886d362c..abd029444 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -18,4 +18,4 @@ pub mod directory; -mod encryptor; +mod store; diff --git a/util/src/keys/encryptor.rs b/util/src/keys/store.rs similarity index 60% rename from util/src/keys/encryptor.rs rename to util/src/keys/store.rs index 7645a2b84..9972b6e57 100644 --- a/util/src/keys/encryptor.rs +++ b/util/src/keys/store.rs @@ -27,6 +27,9 @@ const KEY_LENGTH: u32 = 32; const KEY_ITERATIONS: u32 = 4096; const KEY_LENGTH_AES: u32 = KEY_LENGTH/2; +const KEY_LENGTH_USIZE: usize = KEY_LENGTH as usize; +const KEY_LENGTH_AES_USIZE: usize = KEY_LENGTH_AES as usize; + pub trait EncryptedHashMap { // Returns existing value for the key, if any fn get(&self, key: &Key, password: &str) -> Option; @@ -61,6 +64,26 @@ impl SecretStore { } } +fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) { + let mut h_mac = Hmac::new(::rcrypto::sha2::Sha256::new(), password.as_bytes()); + let mut derived_key = vec![0u8; KEY_LENGTH_USIZE]; + pbkdf2(&mut h_mac, &salt.as_slice(), c, &mut derived_key); + let derived_right_bits = &derived_key[0..KEY_LENGTH_AES_USIZE]; + let derived_left_bits = &derived_key[KEY_LENGTH_AES_USIZE..KEY_LENGTH_USIZE]; + (derived_right_bits.to_vec(), derived_left_bits.to_vec()) +} + +fn derive_key(password: &str, salt: &H256) -> (Bytes, Bytes) { + derive_key_iterations(password, salt, KEY_ITERATIONS) +} + +fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes { + let mut mac = vec![0u8; KEY_LENGTH_AES_USIZE + cipher_text.len()]; + mac[0..KEY_LENGTH_AES_USIZE].clone_from_slice(derived_left_bits); + mac[KEY_LENGTH_AES_USIZE..cipher_text.len()+KEY_LENGTH_AES_USIZE].clone_from_slice(cipher_text); + mac +} + impl EncryptedHashMap for SecretStore { fn get(&self, key: &H128, password: &str) -> Option { match self.directory.get(key) { @@ -81,14 +104,13 @@ impl EncryptedHashMap for SecretStore { let iv = H128::random(); let mut key_file = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(vec![], iv.clone(), salt.clone(), KEY_ITERATIONS, KEY_LENGTH)); - let mut mac = Hmac::new(::rcrypto::sha2::Sha256::new(), password.as_bytes()); - let mut derived_key = vec![0u8; KEY_LENGTH as usize]; - pbkdf2(&mut mac, &salt.as_slice(), KEY_ITERATIONS, &mut derived_key); - let key = &derived_key[KEY_LENGTH_AES as usize..KEY_LENGTH as usize]; + let (derived_left_bits, derived_right_bits) = derive_key(password, &salt); let mut cipher_text = vec![0u8; value.as_slice().len()]; - crypto::aes::encrypt(&key, &iv.as_slice(), &value.as_slice(), &mut cipher_text); - key_file.crypto.cipher_text = cipher_text; + crypto::aes::encrypt(&derived_left_bits, &iv.as_slice(), &value.as_slice(), &mut cipher_text); + key_file.crypto.cipher_text = cipher_text.clone(); + + key_file.crypto.mac = derive_mac(&derived_right_bits, &cipher_text).sha3(); previous } @@ -103,6 +125,31 @@ impl EncryptedHashMap for SecretStore { } +#[cfg(test)] +mod vector_tests { + use super::{derive_key,derive_mac,derive_key_iterations}; + use common::*; + + + #[test] + fn mac_vector() { + let password = "testpassword"; + let salt = H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(); + let cipher_text = FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(); + let iterations = 262144u32; + + let (derived_left_bits, derived_right_bits) = derive_key_iterations(password, &salt, iterations); + assert_eq!("f06d69cdc7da0faffb1008270bca38f5", derived_left_bits.to_hex()); + assert_eq!("e31891a3a773950e6d0fea48a7188551", derived_right_bits.to_hex()); + + let mut mac_body = derive_mac(&derived_right_bits, &cipher_text); + assert_eq!("e31891a3a773950e6d0fea48a71885515318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", mac_body.to_hex()); + + let mac = mac_body.sha3(); + assert_eq!("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2", format!("{:?}", mac)); + } +} + #[cfg(test)] mod tests { @@ -118,4 +165,6 @@ mod tests { sstore.insert(H128::random(), "Cat".to_owned(), "pass"); } + + } From d95e9710306e95552a2ba3ad4df66067c77bea96 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 17:53:31 +0100 Subject: [PATCH 049/753] Prevent deadlocks --- ethcore/src/block_queue.rs | 8 ++++---- util/src/io/worker.rs | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 1a1dee48e..f11519067 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -153,7 +153,7 @@ impl BlockQueue { } fn verify(verification: Arc>, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { - while !deleting.load(AtomicOrdering::Relaxed) { + while !deleting.load(AtomicOrdering::Acquire) { { let mut lock = verification.lock().unwrap(); @@ -161,11 +161,11 @@ impl BlockQueue { empty.notify_all(); } - while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) { + while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) { lock = wait.wait(lock).unwrap(); } - if deleting.load(AtomicOrdering::Relaxed) { + if deleting.load(AtomicOrdering::Acquire) { return; } } @@ -347,7 +347,7 @@ impl MayPanic for BlockQueue { impl Drop for BlockQueue { fn drop(&mut self) { self.clear(); - self.deleting.store(true, AtomicOrdering::Relaxed); + self.deleting.store(true, AtomicOrdering::Release); self.more_to_verify.notify_all(); for t in self.verifiers.drain(..) { t.join().unwrap(); diff --git a/util/src/io/worker.rs b/util/src/io/worker.rs index 1ba0318bc..b874ea0a4 100644 --- a/util/src/io/worker.rs +++ b/util/src/io/worker.rs @@ -44,6 +44,7 @@ pub struct Worker { thread: Option>, wait: Arc, deleting: Arc, + wait_mutex: Arc>, } impl Worker { @@ -61,6 +62,7 @@ impl Worker { thread: None, wait: wait.clone(), deleting: deleting.clone(), + wait_mutex: wait_mutex.clone(), }; worker.thread = Some(thread::Builder::new().name(format!("IO Worker #{}", index)).spawn( move || { @@ -77,13 +79,17 @@ impl Worker { wait_mutex: Arc>, deleting: Arc) where Message: Send + Sync + Clone + 'static { - while !deleting.load(AtomicOrdering::Relaxed) { + loop { { let lock = wait_mutex.lock().unwrap(); - let _ = wait.wait(lock).unwrap(); - if deleting.load(AtomicOrdering::Relaxed) { + if deleting.load(AtomicOrdering::Acquire) { return; } + let _ = wait.wait(lock).unwrap(); + } + + if deleting.load(AtomicOrdering::Acquire) { + return; } while let chase_lev::Steal::Data(work) = stealer.steal() { Worker::do_work(work, channel.clone()); @@ -114,7 +120,8 @@ impl Worker { impl Drop for Worker { fn drop(&mut self) { - self.deleting.store(true, AtomicOrdering::Relaxed); + let _ = self.wait_mutex.lock(); + self.deleting.store(true, AtomicOrdering::Release); self.wait.notify_all(); let thread = mem::replace(&mut self.thread, None).unwrap(); thread.join().ok(); From a4ea0737b25ae4953e16f3b87ebaa84e8994c745 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 17:54:34 +0100 Subject: [PATCH 050/753] Fixed some tests --- util/src/network/host.rs | 6 +++--- util/src/network/tests.rs | 10 ++++++---- util/src/sha3.rs | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 24f24fc6f..140625eea 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -493,8 +493,8 @@ impl Host where Message: Send + Sync + Clone { }; match TcpStream::connect(&address) { Ok(socket) => socket, - Err(_) => { - warn!("Cannot connect to node"); + Err(e) => { + warn!("Can't connect to node: {:?}", e); return; } } @@ -769,9 +769,9 @@ impl IoHandler> for Host where Messa /// Initialize networking fn initialize(&self, io: &IoContext>) { io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); - io.register_stream(DISCOVERY).expect("Error registering UDP listener"); io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer"); if self.discovery.is_some() { + io.register_stream(DISCOVERY).expect("Error registering UDP listener"); io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index a3d5290c9..925c95396 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -92,16 +92,18 @@ fn net_service() { #[test] fn net_connect() { let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_with_port(30344); + let mut config1 = NetworkConfiguration::new_with_port(30354); config1.use_secret = Some(key1.secret().clone()); + config1.nat_enabled = false; config1.boot_nodes = vec![ ]; - let mut config2 = NetworkConfiguration::new_with_port(30345); - config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30344", key1.public().hex()) ]; + let mut config2 = NetworkConfiguration::new_with_port(30355); + config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30354", key1.public().hex()) ]; + config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1); let handler2 = TestProtocol::register(&mut service2); - while !handler1.got_packet() && !handler2.got_packet() { + while !handler1.got_packet() && !handler2.got_packet() && (service1.stats().sessions() == 0 || service2.stats().sessions() == 0) { thread::sleep(Duration::from_millis(50)); } assert!(service1.stats().sessions() >= 1); diff --git a/util/src/sha3.rs b/util/src/sha3.rs index 4079e8ba4..7e8382250 100644 --- a/util/src/sha3.rs +++ b/util/src/sha3.rs @@ -66,7 +66,7 @@ impl Hashable for T where T: BytesConvertable { #[test] fn sha3_empty() { - assert_eq!((&[0u8; 0]).sha3(), SHA3_EMPTY); + assert_eq!([0u8; 0].sha3(), SHA3_EMPTY); } #[test] fn sha3_as() { From f4fa747cd0683b16d670ae4f446dd5155ffd1df4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 17:55:37 +0100 Subject: [PATCH 051/753] ip_utils tests --- util/src/network/ip_utils.rs | 50 ++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs index 8f94073b3..da50f8ddf 100644 --- a/util/src/network/ip_utils.rs +++ b/util/src/network/ip_utils.rs @@ -43,34 +43,28 @@ mod getinterfaces { let sa: *const sockaddr_in = unsafe { mem::transmute(sa) }; let sa = & unsafe { *sa }; let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port); - ( - IpAddr::V4(Ipv4Addr::new( - (addr & 0x000000FF) as u8, - ((addr & 0x0000FF00) >> 8) as u8, - ((addr & 0x00FF0000) >> 16) as u8, - ((addr & 0xFF000000) >> 24) as u8, - )), - port - ) + (IpAddr::V4(Ipv4Addr::new( + (addr & 0x000000FF) as u8, + ((addr & 0x0000FF00) >> 8) as u8, + ((addr & 0x00FF0000) >> 16) as u8, + ((addr & 0xFF000000) >> 24) as u8)), + port) }, AF_INET6 => { let sa: *const sockaddr_in6 = unsafe { mem::transmute(sa) }; let sa = & unsafe { *sa }; let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port); let addr: [u16; 8] = unsafe { mem::transmute(addr) }; - ( - IpAddr::V6(Ipv6Addr::new( - addr[0], - addr[1], - addr[2], - addr[3], - addr[4], - addr[5], - addr[6], - addr[7], - )), - port - ) + (IpAddr::V6(Ipv6Addr::new( + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5], + addr[6], + addr[7])), + port) }, _ => return None, }; @@ -174,3 +168,15 @@ pub fn map_external_address(local: &NodeEndpoint) -> Option { None } +#[test] +fn can_select_public_address() { + let pub_address = select_public_address(40477); + assert!(pub_address.port() == 40477); +} + +#[test] +fn can_map_external_address_or_fail() { + let pub_address = select_public_address(40478); + let _ = map_external_address(&NodeEndpoint { address: pub_address, udp_port: 40478 }); +} + From b01652f3e7a0bde9f28c7c236174fbe466b819a5 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 16 Feb 2016 18:21:45 +0100 Subject: [PATCH 052/753] LocalizedLogEntry and Filter in ethcore module --- ethcore/src/externalities.rs | 6 +- ethcore/src/filter.rs | 152 +++++++++++++++++++++++++++++++++++ ethcore/src/lib.rs | 1 + ethcore/src/log_entry.rs | 40 ++++++--- ethcore/src/receipt.rs | 10 +-- ethcore/src/substate.rs | 12 ++- 6 files changed, 203 insertions(+), 18 deletions(-) create mode 100644 ethcore/src/filter.rs diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 360bd9738..5205c67cb 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -226,7 +226,11 @@ impl<'a> Ext for Externalities<'a> { fn log(&mut self, topics: Vec, data: &[u8]) { let address = self.origin_info.address.clone(); - self.substate.logs.push(LogEntry::new(address, topics, data.to_vec())); + self.substate.logs.push(LogEntry { + address: address, + topics: topics, + data: data.to_vec() + }); } fn suicide(&mut self, refund_address: &Address) { diff --git a/ethcore/src/filter.rs b/ethcore/src/filter.rs new file mode 100644 index 000000000..718656191 --- /dev/null +++ b/ethcore/src/filter.rs @@ -0,0 +1,152 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::hash::*; +use util::sha3::*; +use client::BlockId; + +/// Blockchain log filter data. +pub struct Filter { + /// Blockchain will be searched from this block. + from_block: BlockId, + + /// Till this block. + to_block: BlockId, + + /// Search addresses. + /// + /// If None, match all. + /// If specified, log must be produced by one of these addresses. + address: Option>, + + /// Search topics. + /// + /// If None, match all. + /// If specified, log must contain one of these topics. + topics: [Option>; 4] +} + +impl Filter { + /// Returns combinations of each address and topic. + pub fn bloom_possibilities(&self) -> Vec { + let blooms = match self.address { + Some(ref addresses) if !addresses.is_empty() => + addresses.iter().map(|ref address| { + let mut bloom = H2048::new(); + bloom.shift_bloomed(&address.sha3()); + bloom + }).collect(), + _ => vec![H2048::new()] + }; + + self.topics.iter().fold(blooms, | bs, topic | match *topic { + None => bs, + Some(ref topics) => bs.into_iter().map(|bloom| { + topics.into_iter().map(|topic| { + let mut b = bloom.clone(); + b.shift_bloomed(&topic.sha3()); + b + }).collect::>() + }).flat_map(|m| m).collect() + }) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use util::hash::*; + use filter::Filter; + use client::BlockId; + + #[test] + fn test_bloom_possibilities_none() { + let none_filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: None, + topics: [None, None, None, None] + }; + + let possibilities = none_filter.bloom_possibilities(); + assert_eq!(possibilities.len(), 1); + assert!(possibilities[0].is_zero()) + } + + // block 399849 + #[test] + fn test_bloom_possibilities_single_address_and_topic() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), + topics: [ + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + None, None, None + ] + }; + + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); + } + + #[test] + fn test_bloom_possibilities_single_address_and_many_topics() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), + topics: [ + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + None, None + ] + }; + + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); + } + + #[test] + fn test_bloom_possibilites_multiple_addresses_and_topics() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![ + Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + ]), + topics: [ + Some(vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() + ]), + Some(vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() + ]), + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + None + ] + }; + + // number of possibilites should be equal 2 * 2 * 2 * 1 = 8 + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities.len(), 8); + assert_eq!(possibilities[0], H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()); + } + +} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 689b1be6a..38f961d10 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -131,6 +131,7 @@ mod substate; mod executive; mod externalities; mod verification; +mod filter; #[cfg(test)] mod tests; diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index ee73b1ad1..304fae9d0 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -38,15 +38,6 @@ impl Encodable for LogEntry { } impl LogEntry { - /// Create a new log entry. - pub fn new(address: Address, topics: Vec, data: Bytes) -> LogEntry { - LogEntry { - address: address, - topics: topics, - data: data - } - } - /// Calculates the bloom of this log entry. pub fn bloom(&self) -> LogBloom { self.topics.iter().fold(LogBloom::from_bloomed(&self.address.sha3()), |b, t| b.with_bloomed(&t.sha3())) @@ -65,6 +56,31 @@ impl FromJson for LogEntry { } } +/// Log localized in a blockchain. +#[derive(Default, Debug, PartialEq)] +pub struct LocalizedLogEntry { + /// Plain log entry. + pub entry: LogEntry, + /// Block in which this log was created. + pub block_hash: H256, + /// Block number. + pub block_number: usize, + /// Hash of transaction in which this log was created. + pub transaction_hash: H256, + /// Index of transaction within block. + pub transaction_index: usize, + /// Log position in the block. + pub log_index: usize +} + +impl Deref for LocalizedLogEntry { + type Target = LogEntry; + + fn deref(&self) -> &Self::Target { + &self.entry + } +} + #[cfg(test)] mod tests { use util::*; @@ -74,7 +90,11 @@ mod tests { fn test_empty_log_bloom() { let bloom = H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let log = LogEntry::new(address, vec![], vec![]); + let log = LogEntry { + address: address, + topics: vec![], + data: vec![] + }; assert_eq!(log.bloom(), bloom); } } diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index 5fc1a318b..f43b58224 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -62,11 +62,11 @@ fn test_basic() { let r = Receipt::new( x!("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee"), x!(0x40cae), - vec![LogEntry::new( - x!("dcf421d093428b096ca501a7cd1a740855a7976f"), - vec![], - vec![0u8; 32] - )] + vec![LogEntry { + address: x!("dcf421d093428b096ca501a7cd1a740855a7976f"), + topics: vec![], + data: vec![0u8; 32] + }] ); assert_eq!(&encode(&r)[..], &expected[..]); } diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 235ce2e97..374397ca7 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -66,13 +66,21 @@ mod tests { fn accrue() { let mut sub_state = Substate::new(); sub_state.contracts_created.push(address_from_u64(1u64)); - sub_state.logs.push(LogEntry::new(address_from_u64(1u64), vec![], vec![])); + sub_state.logs.push(LogEntry { + address: address_from_u64(1u64), + topics: vec![], + data: vec![] + }); sub_state.sstore_clears_count = x!(5); sub_state.suicides.insert(address_from_u64(10u64)); let mut sub_state_2 = Substate::new(); sub_state_2.contracts_created.push(address_from_u64(2u64)); - sub_state_2.logs.push(LogEntry::new(address_from_u64(1u64), vec![], vec![])); + sub_state_2.logs.push(LogEntry { + address: address_from_u64(1u64), + topics: vec![], + data: vec![] + }); sub_state_2.sstore_clears_count = x!(7); sub_state.accrue(sub_state_2); From 9895f00e5ebebd8a4d42a46422ffed5d946e282c Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 16 Feb 2016 20:52:36 +0300 Subject: [PATCH 053/753] warnings, docs, and finding bugs --- util/src/keys/directory.rs | 36 +++++++--- util/src/keys/mod.rs | 3 +- util/src/keys/store.rs | 142 ++++++++++++++++++++++++++++++------- 3 files changed, 143 insertions(+), 38 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 641a5cae4..7656a938f 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -273,7 +273,7 @@ impl KeyFileCrypto { /// `c` - number of iterations for derived key. /// `salt` - cryptographic site, random 256-bit hash (ensure it's crypto-random). /// `iv` - initialisation vector. - pub fn new_pbkdf2(cipher_text: Bytes, iv: H128, salt: H256, c: u32, dk_len: u32) -> KeyFileCrypto { + pub fn new_pbkdf2(cipher_text: Bytes, iv: H128, salt: H256, mac: H256, c: u32, dk_len: u32) -> KeyFileCrypto { KeyFileCrypto { cipher_type: CryptoCipherType::Aes128Ctr(iv), cipher_text: cipher_text, @@ -283,7 +283,7 @@ impl KeyFileCrypto { c: c, prf: Pbkdf2CryptoFunction::HMacSha256 }), - mac: H256::random(), + mac: mac, } } } @@ -530,6 +530,22 @@ impl KeyDirectory { self.cache.borrow().len() } + /// Removes key file from key directory + pub fn delete(&mut self, id: &Uuid) -> Result<(), ::std::io::Error> { + let path = self.key_path(id); + + if !self.cache.borrow().contains_key(id) { + return match fs::remove_file(&path) { + Ok(_) => { + self.cache.borrow_mut().remove(&id); + Ok(()) + }, + Err(e) => Err(e) + }; + } + Ok(()) + } + fn key_path(&self, id: &Uuid) -> PathBuf { let mut path = PathBuf::new(); path.push(self.path.clone()); @@ -849,14 +865,14 @@ mod file_tests { #[test] fn can_create_key_with_new_id() { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32)); assert!(!uuid_to_string(&key.id).is_empty()); } #[test] fn can_load_json_from_itself() { let cipher_text: Bytes = FromHex::from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaa22222222222222222222222").unwrap(); - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32)); let json = key.to_json(); let loaded_key = KeyFileContent::from_json(&json).unwrap(); @@ -1014,7 +1030,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32))).unwrap(); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32))).unwrap(); let path = directory.key_path(&uuid); let key = KeyDirectory::load_key(&path).unwrap(); @@ -1030,7 +1046,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..1000 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } @@ -1050,7 +1066,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..1000 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } @@ -1083,7 +1099,7 @@ mod specs { let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), 32, 32))); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32))); assert!(uuid.is_ok()); } @@ -1093,7 +1109,7 @@ mod specs { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32))).unwrap(); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32))).unwrap(); let key = directory.get(&uuid).unwrap(); @@ -1108,7 +1124,7 @@ mod specs { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..10 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index abd029444..fd52136d7 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -17,5 +17,4 @@ //! Key management module pub mod directory; - -mod store; +pub mod store; diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 9972b6e57..f473d0ea2 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -14,12 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Generic Encryptor +//! Secret Store use keys::directory::*; use common::*; use rcrypto::pbkdf2::*; -use rcrypto::aes; use rcrypto::hmac::*; use crypto; @@ -30,25 +29,37 @@ const KEY_LENGTH_AES: u32 = KEY_LENGTH/2; const KEY_LENGTH_USIZE: usize = KEY_LENGTH as usize; const KEY_LENGTH_AES_USIZE: usize = KEY_LENGTH_AES as usize; +/// Encrypted hash-map, each request should contain password pub trait EncryptedHashMap { - // Returns existing value for the key, if any - fn get(&self, key: &Key, password: &str) -> Option; - // Insert new encrypted key-value and returns previous if there was any + /// Returns existing value for the key, if any + fn get(&self, key: &Key, password: &str) -> Result; + /// Insert new encrypted key-value and returns previous if there was any fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; - // Removes key-value by key and returns the removed one, if any exists and password was provided + /// Removes key-value by key and returns the removed one, if any exists and password was provided fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; - // Deletes key-value by key and returns if the key-value existed + /// Deletes key-value by key and returns if the key-value existed fn delete(&mut self, key: &Key) -> bool { self.remove::<&[u8]>(key, None).is_some() } } +/// Error retrieving value from encrypted hashmap +#[derive(Debug)] +pub enum EncryptedHashMapError { + /// Encryption failed + InvalidPassword, + /// No key in the hashmap + UnknownIdentifier +} + +/// Represent service for storing encrypted arbitrary data pub struct SecretStore { directory: KeyDirectory } impl SecretStore { - fn new() -> SecretStore { + /// new instance of Secret Store + pub fn new() -> SecretStore { let mut path = ::std::env::home_dir().expect("Failed to get home dir"); path.push(".keys"); SecretStore { @@ -85,41 +96,75 @@ fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes { } impl EncryptedHashMap for SecretStore { - fn get(&self, key: &H128, password: &str) -> Option { + fn get(&self, key: &H128, password: &str) -> Result { match self.directory.get(key) { Some(key_file) => { - let mut instance = Value::default(); - instance.populate_raw(&key_file.crypto.cipher_text); - Some(instance) - }, - None => None - } + let decrypted_bytes = match key_file.crypto.kdf { + KeyFileKdf::Pbkdf2(ref params) => { + let (derived_left_bits, derived_right_bits) = derive_key(password, ¶ms.salt); + let expected_mac = derive_mac(&derived_right_bits, &key_file.crypto.cipher_text).sha3(); + if expected_mac != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } + let mut val = vec![0u8; key_file.crypto.cipher_text.len()]; + match key_file.crypto.cipher_type { + CryptoCipherType::Aes128Ctr(ref iv) => { + crypto::aes::decrypt(&derived_left_bits, &iv.as_slice(), &key_file.crypto.cipher_text, &mut val); + } + } + val + } + _ => { unimplemented!(); } + }; + + let mut instance = Value::default(); + instance.populate_raw(&decrypted_bytes); + Ok(instance) + }, + None => Err(EncryptedHashMapError::UnknownIdentifier) + } } fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { - let previous = if let Some(_) = self.directory.get(&key) { self.get(&key, password) } else { None }; + let previous = if let Ok(previous_value) = self.get(&key, password) { Some(previous_value) } else { None }; + // crypto random initiators let salt = H256::random(); let iv = H128::random(); - let mut key_file = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(vec![], iv.clone(), salt.clone(), KEY_ITERATIONS, KEY_LENGTH)); + // two parts of derived key + // DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits] let (derived_left_bits, derived_right_bits) = derive_key(password, &salt); let mut cipher_text = vec![0u8; value.as_slice().len()]; - crypto::aes::encrypt(&derived_left_bits, &iv.as_slice(), &value.as_slice(), &mut cipher_text); - key_file.crypto.cipher_text = cipher_text.clone(); + // aes-128-ctr with initial vector of iv + crypto::aes::encrypt(&derived_left_bits, &iv.clone(), &value.as_slice(), &mut cipher_text); - key_file.crypto.mac = derive_mac(&derived_right_bits, &cipher_text).sha3(); + // KECCAK(DK[16..31] ++ ), where DK[16..31] - derived_right_bits + let mac = derive_mac(&derived_right_bits, &cipher_text.clone()).sha3(); + let key_file = KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + cipher_text, + iv, + salt, + mac, + KEY_ITERATIONS, + KEY_LENGTH)); + if let Err(io_error) = self.directory.save(key_file) { + warn!("Error saving key file: {:?}", io_error); + } previous } fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { - let previous = match (self.directory.get(&key), password) { - (Some(_), Some(pass)) => self.get(&key, pass), - (_, _) => None - }; + let previous = if let Some(pass) = password { + if let Ok(previous_value) = self.get(&key, pass) { Some(previous_value) } else { None } + } + else { None }; + + if let Err(io_error) = self.directory.delete(key) { + warn!("Error saving key file: {:?}", io_error); + } previous } @@ -127,7 +172,7 @@ impl EncryptedHashMap for SecretStore { #[cfg(test)] mod vector_tests { - use super::{derive_key,derive_mac,derive_key_iterations}; + use super::{derive_mac,derive_key_iterations}; use common::*; @@ -142,7 +187,7 @@ mod vector_tests { assert_eq!("f06d69cdc7da0faffb1008270bca38f5", derived_left_bits.to_hex()); assert_eq!("e31891a3a773950e6d0fea48a7188551", derived_right_bits.to_hex()); - let mut mac_body = derive_mac(&derived_right_bits, &cipher_text); + let mac_body = derive_mac(&derived_right_bits, &cipher_text); assert_eq!("e31891a3a773950e6d0fea48a71885515318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", mac_body.to_hex()); let mac = mac_body.sha3(); @@ -165,6 +210,51 @@ mod tests { sstore.insert(H128::random(), "Cat".to_owned(), "pass"); } + #[test] + fn secret_store_get_fail() { + let temp = RandomTempPath::create_dir(); + { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + write_sstore.directory.save( + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32))) + .unwrap(); + } + let sstore = SecretStore::new_test(&temp); + if let Ok(_) = sstore.get::(&H128::from_str("3198bc9c66725ab3d9954942343ae5b6").unwrap(), "testpassword") { + panic!("shoud be error loading key, we requested the wrong key"); + } + } + + #[test] + fn secret_store_get() { + let temp = RandomTempPath::create_dir(); + let key_id = { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + write_sstore.directory.save( + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32))) + .unwrap() + }; + let sstore = SecretStore::new_test(&temp); + if let Err(e) = sstore.get::(&key_id, "testpassword") { + panic!("got no key: {:?}", e); + } + } } From 217cbec50ed6c2cccec386dd3daedbf95b92c64e Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 19:08:58 +0100 Subject: [PATCH 054/753] Disconnect test --- util/src/network/host.rs | 1 - util/src/network/session.rs | 5 +++ util/src/network/tests.rs | 65 +++++++++++++++++++++++++++---------- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 140625eea..4afb790ae 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -634,7 +634,6 @@ impl Host where Message: Send + Sync + Clone { } if kill { self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection - return; } for p in ready_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); diff --git a/util/src/network/session.rs b/util/src/network/session.rs index f08fef385..04fb6d930 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -318,7 +318,12 @@ impl Session { trace!(target: "net", "Hello: {} v{} {} {:?}", client_version, protocol, id, caps); self.info.client_version = client_version; self.info.capabilities = caps; + if self.info.capabilities.is_empty() { + trace!("No common capabilities with peer."); + return Err(From::from(self.disconnect(DisconnectReason::UselessPeer))); + } if protocol != host.protocol_version { + trace!("Peer protocol version mismatch: {}", protocol); return Err(From::from(self.disconnect(DisconnectReason::UselessPeer))); } self.had_hello = true; diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index 925c95396..dc80936d2 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -23,17 +23,10 @@ use io::TimerToken; use crypto::KeyPair; pub struct TestProtocol { + drop_session: bool, pub packet: Mutex, pub got_timeout: AtomicBool, -} - -impl Default for TestProtocol { - fn default() -> Self { - TestProtocol { - packet: Mutex::new(Vec::new()), - got_timeout: AtomicBool::new(false), - } - } + pub got_disconnect: AtomicBool, } #[derive(Clone)] @@ -42,9 +35,17 @@ pub struct TestProtocolMessage { } impl TestProtocol { + pub fn new(drop_session: bool) -> Self { + TestProtocol { + packet: Mutex::new(Vec::new()), + got_timeout: AtomicBool::new(false), + got_disconnect: AtomicBool::new(false), + drop_session: drop_session, + } + } /// Creates and register protocol with the network service - pub fn register(service: &mut NetworkService) -> Arc { - let handler = Arc::new(TestProtocol::default()); + pub fn register(service: &mut NetworkService, drop_session: bool) -> Arc { + let handler = Arc::new(TestProtocol::new(drop_session)); service.register_protocol(handler.clone(), "test", &[42u8, 43u8]).expect("Error registering test protocol handler"); handler } @@ -56,6 +57,10 @@ impl TestProtocol { pub fn got_timeout(&self) -> bool { self.got_timeout.load(AtomicOrdering::Relaxed) } + + pub fn got_disconnect(&self) -> bool { + self.got_disconnect.load(AtomicOrdering::Relaxed) + } } impl NetworkProtocolHandler for TestProtocol { @@ -68,11 +73,16 @@ impl NetworkProtocolHandler for TestProtocol { self.packet.lock().unwrap().extend(data); } - fn connected(&self, io: &NetworkContext, _peer: &PeerId) { - io.respond(33, "hello".to_owned().into_bytes()).unwrap(); + fn connected(&self, io: &NetworkContext, peer: &PeerId) { + if self.drop_session { + io.disconnect_peer(*peer) + } else { + io.respond(33, "hello".to_owned().into_bytes()).unwrap(); + } } fn disconnected(&self, _io: &NetworkContext, _peer: &PeerId) { + self.got_disconnect.store(true, AtomicOrdering::Relaxed); } /// Timer function called after a timeout created with `NetworkContext::timeout`. @@ -86,7 +96,7 @@ impl NetworkProtocolHandler for TestProtocol { #[test] fn net_service() { let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40414)).expect("Error creating network service"); - service.register_protocol(Arc::new(TestProtocol::default()), "myproto", &[1u8]).unwrap(); + service.register_protocol(Arc::new(TestProtocol::new(false)), "myproto", &[1u8]).unwrap(); } #[test] @@ -101,8 +111,8 @@ fn net_connect() { config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); let mut service2 = NetworkService::::start(config2).unwrap(); - let handler1 = TestProtocol::register(&mut service1); - let handler2 = TestProtocol::register(&mut service2); + let handler1 = TestProtocol::register(&mut service1, false); + let handler2 = TestProtocol::register(&mut service2, false); while !handler1.got_packet() && !handler2.got_packet() && (service1.stats().sessions() == 0 || service2.stats().sessions() == 0) { thread::sleep(Duration::from_millis(50)); } @@ -110,11 +120,32 @@ fn net_connect() { assert!(service2.stats().sessions() >= 1); } +#[test] +fn net_disconnect() { + let key1 = KeyPair::create().unwrap(); + let mut config1 = NetworkConfiguration::new_with_port(30364); + config1.use_secret = Some(key1.secret().clone()); + config1.nat_enabled = false; + config1.boot_nodes = vec![ ]; + let mut config2 = NetworkConfiguration::new_with_port(30365); + config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30364", key1.public().hex()) ]; + config2.nat_enabled = false; + let mut service1 = NetworkService::::start(config1).unwrap(); + let mut service2 = NetworkService::::start(config2).unwrap(); + let handler1 = TestProtocol::register(&mut service1, false); + let handler2 = TestProtocol::register(&mut service2, true); + while !(handler1.got_disconnect() && handler2.got_disconnect()) { + thread::sleep(Duration::from_millis(50)); + } + assert!(handler1.got_disconnect()); + assert!(handler2.got_disconnect()); +} + #[test] fn net_timeout() { let config = NetworkConfiguration::new_with_port(30346); let mut service = NetworkService::::start(config).unwrap(); - let handler = TestProtocol::register(&mut service); + let handler = TestProtocol::register(&mut service, false); while !handler.got_timeout() { thread::sleep(Duration::from_millis(50)); } From 4f73d63f90154140d6dadeaed3700ca623eed0ab Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 19:51:51 +0100 Subject: [PATCH 055/753] Tweaked CLI options --- parity/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 5fec05eb4..516609615 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -64,9 +64,11 @@ Options: -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --no-bootstrap Don't bother trying to connect to any nodes initially. - --listen-address URL Specify the IP/port on which to listen for peers. + --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect. --address URL Equivalent to --listen-address URL --public-address URL. + --peers NUM Try to manintain that many peers [default: 25]. + --no-discovery Disable new peer discovery. --upnp Use UPnP to try to figure out the correct network settings. --node-key KEY Specify node secret key as hex string. @@ -81,8 +83,8 @@ Options: -h --help Show this screen. ", flag_cache_pref_size: usize, flag_cache_max_size: usize, + flag_peers: u32, flag_address: Option, - flag_listen_address: Option, flag_public_address: Option, flag_node_key: Option); @@ -168,11 +170,8 @@ impl Configuration { public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address")); listen_address = public_address; } - if let Some(ref a) = self.args.flag_listen_address { - if listen_address.is_some() { - panic!("Conflicting flags: --address and --listen-address"); - } - listen_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --listen-address")); + if listen_address.is_none() { + listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).expect("Invalid listen address given with --listen-address")); } if let Some(ref a) = self.args.flag_public_address { if public_address.is_some() { @@ -218,6 +217,8 @@ fn main() { net_settings.listen_address = listen; net_settings.public_address = public; net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); + net_settings.discovery_enabled = !conf.args.flag_no_discovery; + net_settings.ideal_peers = conf.args.flag_peers; let mut net_path = PathBuf::from(&conf.path()); net_path.push("network"); net_settings.config_path = Some(net_path.to_str().unwrap().to_owned()); From fbe06d3f2f85275cc6ec4c9c3b17344a3778def0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 21:25:01 +0100 Subject: [PATCH 056/753] More tests --- util/src/network/discovery.rs | 22 +++++++++++++++++----- util/src/network/host.rs | 10 ++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index c15dbbbc4..0064a34db 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -445,13 +445,13 @@ impl Discovery { Ok(Some(TableUpdates { added: added, removed: HashSet::new() })) } - fn check_expired(&mut self) -> HashSet { + fn check_expired(&mut self, force: bool) -> HashSet { let now = time::precise_time_ns(); let mut removed: HashSet = HashSet::new(); for bucket in &mut self.node_buckets { bucket.nodes.retain(|node| { if let Some(timeout) = node.timeout { - if now - timeout < PING_TIMEOUT_MS * 1000_0000 { + if !force && now - timeout < PING_TIMEOUT_MS * 1000_0000 { true } else { @@ -466,7 +466,7 @@ impl Discovery { } pub fn round(&mut self) -> Option { - let removed = self.check_expired(); + let removed = self.check_expired(false); self.discover(); if !removed.is_empty() { Some(TableUpdates { added: HashMap::new(), removed: removed }) @@ -512,8 +512,8 @@ mod tests { let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap(); - discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1. endpoint.clone() }); - discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2. endpoint.clone() }); + discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1.endpoint.clone() }); + discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2.endpoint.clone() }); discovery2.add_node(NodeEntry { id: key1.public().clone(), endpoint: ep1.clone() }); discovery2.refresh(); @@ -535,4 +535,16 @@ mod tests { } assert_eq!(Discovery::nearest_node_entries(&NodeId::new(), &discovery2.node_buckets).len(), 3) } + + #[test] + fn removes_expired() { + let key = KeyPair::create().unwrap(); + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40444 }; + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0); + for _ in 0..1200 { + discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); + } + let removed = discovery.check_expired(true).len(); + assert!(removed > 0); + } } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 4afb790ae..080a8b5cc 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -987,3 +987,13 @@ fn load_key(path: &Path) -> Option { } } } + +#[test] +fn key_save_load() { + use tests::helpers::RandomTempPath; + let temp_path = RandomTempPath::create_dir(); + let key = H256::random(); + save_key(temp_path.as_path(), &key); + let r = load_key(temp_path.as_path()); + assert_eq!(key, r.unwrap()); +} From 8802fb2fd83500c6cc373e9b23ebc5ab93772e63 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 13 Feb 2016 02:31:23 +0530 Subject: [PATCH 057/753] Make clippy an optional dependency --- .travis.yml | 2 +- Cargo.lock | 4 ---- Cargo.toml | 3 ++- ethcore/Cargo.toml | 3 ++- ethcore/src/lib.rs | 5 ++--- parity/main.rs | 2 +- rpc/Cargo.toml | 6 +++++- rpc/src/lib.rs | 2 +- sync/Cargo.toml | 6 +++++- sync/src/lib.rs | 4 ++-- util/Cargo.toml | 6 +++++- util/src/lib.rs | 4 ++-- 12 files changed, 28 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index b2859589b..0abda2c30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ matrix: fast_finish: true include: - rust: nightly - env: FEATURES="--features ethcore/json-tests" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES='--features "ethcore/json-tests dev"' KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: apt: true directories: diff --git a/Cargo.lock b/Cargo.lock index 1e9f57900..94b9a3b91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,7 +167,6 @@ dependencies = [ name = "ethcore" version = "0.9.99" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", @@ -186,7 +185,6 @@ dependencies = [ name = "ethcore-rpc" version = "0.9.99" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", @@ -204,7 +202,6 @@ name = "ethcore-util" version = "0.9.99" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -232,7 +229,6 @@ dependencies = [ name = "ethsync" version = "0.9.99" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", diff --git a/Cargo.toml b/Cargo.toml index c58cacf0d..a3fd40e34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ rustc-serialize = "0.3" docopt = "0.6" docopt_macros = "0.6" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } -clippy = "0.0.41" +clippy = { version = "0.0.41", optional = true } ethcore-util = { path = "util" } ethcore = { path = "ethcore" } ethsync = { path = "sync" } @@ -23,6 +23,7 @@ target_info = "0.1" [features] default = ["rpc"] rpc = ["ethcore-rpc"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] [[bin]] path = "parity/main.rs" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 3d4d27520..4aafebba1 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -18,7 +18,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = "0.0.41" +clippy = { version = "0.0.41", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" @@ -27,3 +27,4 @@ jit = ["evmjit"] evm-debug = [] json-tests = [] test-heavy = [] +dev = ["clippy"] diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 4cca74319..093906bd0 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -17,9 +17,8 @@ #![warn(missing_docs)] #![feature(cell_extras)] #![feature(augmented_assignments)] -#![feature(plugin)] -// Clippy -#![plugin(clippy)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // TODO [todr] not really sure #![allow(needless_range_loop)] // Shorter than if-else diff --git a/parity/main.rs b/parity/main.rs index 460922b64..eadaa4968 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -19,7 +19,7 @@ #![warn(missing_docs)] #![feature(plugin)] #![plugin(docopt_macros)] -#![plugin(clippy)] +#![cfg_attr(feature="dev", plugin(clippy))] extern crate docopt; extern crate rustc_serialize; extern crate ethcore_util as util; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b1af0a2fa..107e22c07 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -16,6 +16,10 @@ jsonrpc-http-server = "1.1.2" ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } -clippy = "0.0.41" +clippy = { version = "0.0.41", optional = true } target_info = "0.1.0" rustc-serialize = "0.3" + +[features] +default = [] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev"] diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 0b148c983..cd059e6b1 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -18,7 +18,7 @@ #![warn(missing_docs)] #![feature(custom_derive, custom_attribute, plugin)] #![plugin(serde_macros)] -#![plugin(clippy)] +#![cfg_attr(feature="dev", plugin(clippy))] extern crate rustc_serialize; extern crate target_info; diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 92b46fc57..fc56ba2b9 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,8 +10,12 @@ authors = ["Ethcore . #![warn(missing_docs)] -#![feature(plugin)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] #![feature(augmented_assignments)] -#![plugin(clippy)] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![allow(clone_on_copy)] diff --git a/util/Cargo.toml b/util/Cargo.toml index 9ead8ccf6..773e58de3 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -26,7 +26,11 @@ crossbeam = "0.2" slab = { git = "https://github.com/arkpar/slab.git" } sha3 = { path = "sha3" } serde = "0.6.7" -clippy = "0.0.41" +clippy = { version = "0.0.41", optional = true } json-tests = { path = "json-tests" } target_info = "0.1.0" igd = "0.4.2" + +[features] +default = [] +dev = ["clippy"] \ No newline at end of file diff --git a/util/src/lib.rs b/util/src/lib.rs index d4f972800..0a2b0f4b4 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -18,10 +18,10 @@ #![feature(op_assign_traits)] #![feature(augmented_assignments)] #![feature(associated_consts)] -#![feature(plugin)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] #![feature(catch_panic)] // Clippy settings -#![plugin(clippy)] // TODO [todr] not really sure #![allow(needless_range_loop)] // Shorter than if-else From 7e0dfb41d08bc4a47084a61a7b745eed00de1690 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 23:33:32 +0100 Subject: [PATCH 058/753] Minor test tweaks and code cleanup --- util/src/network/discovery.rs | 1 + util/src/network/host.rs | 26 ++++---------------------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 0064a34db..f383b74f7 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -544,6 +544,7 @@ mod tests { for _ in 0..1200 { discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); } + assert!(Discovery::nearest_node_entries(&NodeId::new(), &discovery.node_buckets).len() <= 16); let removed = discovery.check_expired(true).len(); assert!(removed > 0); } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 080a8b5cc..bcb1c7585 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -534,42 +534,24 @@ impl Host where Message: Send + Sync + Clone { } fn handshake_writable(&self, token: StreamToken, io: &IoContext>) { - let mut create_session = false; - let mut kill = false; let handshake = { self.handshakes.read().unwrap().get(token).cloned() }; if let Some(handshake) = handshake { let mut h = handshake.lock().unwrap(); if let Err(e) = h.writable(io, &self.info.read().unwrap()) { debug!(target: "net", "Handshake write error: {}:{:?}", token, e); - kill = true; - } - if h.done() { - create_session = true; } } - if kill { - self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection - return; - } else if create_session { - self.start_session(token, io); - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); - } } fn session_writable(&self, token: StreamToken, io: &IoContext>) { - let mut kill = false; let session = { self.sessions.read().unwrap().get(token).cloned() }; if let Some(session) = session { let mut s = session.lock().unwrap(); if let Err(e) = s.writable(io, &self.info.read().unwrap()) { debug!(target: "net", "Session write error: {}:{:?}", token, e); - kill = true; } io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); } - if kill { - self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection - } } fn connection_closed(&self, token: TimerToken, io: &IoContext>) { @@ -793,7 +775,7 @@ impl IoHandler> for Host where Messa if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().readable() { self.update_nodes(io, node_changes); } - io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, TCP_ACCEPT => self.accept(io), _ => panic!("Received unknown readable token"), @@ -806,7 +788,7 @@ impl IoHandler> for Host where Messa FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io), DISCOVERY => { self.discovery.as_ref().unwrap().lock().unwrap().writable(); - io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); } _ => panic!("Received unknown writable token"), } @@ -819,13 +801,13 @@ impl IoHandler> for Host where Messa FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { self.discovery.as_ref().unwrap().lock().unwrap().refresh(); - io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, DISCOVERY_ROUND => { if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().round() { self.update_nodes(io, node_changes); } - io.update_registration(DISCOVERY).expect("Error updating disicovery registration"); + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, _ => match self.timers.read().unwrap().get(&token).cloned() { Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() { From b6ccbdb6949a3d2a3a9b85b34fa7a6ece0fd1e0c Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 16 Feb 2016 23:37:24 +0100 Subject: [PATCH 059/753] Lower max handshakes to reduce network load --- util/src/network/host.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index bcb1c7585..9560ca81e 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -46,8 +46,8 @@ type Slab = ::slab::Slab; const _DEFAULT_PORT: u16 = 30304; const MAX_SESSIONS: usize = 1024; -const MAX_HANDSHAKES: usize = 256; -const MAX_HANDSHAKES_PER_ROUND: usize = 64; +const MAX_HANDSHAKES: usize = 64; +const MAX_HANDSHAKES_PER_ROUND: usize = 8; const MAINTENANCE_TIMEOUT: u64 = 1000; #[derive(Debug)] From 63f6ab4e6d70d8a2e3a148a76dec82decd500326 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 02:32:16 +0300 Subject: [PATCH 060/753] resolved with bytes-encodable issue --- util/src/bytes.rs | 43 ++++++++++++++++++++++++++++++++++++++ util/src/keys/directory.rs | 2 +- util/src/keys/store.rs | 35 ++++++++++++++++++------------- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 0006827e8..a26804c5b 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -256,6 +256,49 @@ impl Populatable for [T] where T: Sized { } } +#[derive(Debug)] +/// Bytes array deserialization error +pub enum FromBytesError { + /// Not enough bytes for the requested type + NotLongEnough, + /// Too many bytes for the requested type + TooLong, +} + +/// Value that can be serialized from bytes array +pub trait FromRawBytes : Sized { + /// function that will instantiate and initialize object from slice + fn from_bytes(d: &[u8]) -> Result; +} + +impl FromRawBytes for T where T: Sized + FixedHash { + fn from_bytes(bytes: &[u8]) -> Result { + use std::mem; + use std::cmp::Ordering; + match bytes.len().cmp(&mem::size_of::()) { + Ordering::Less => return Err(FromBytesError::NotLongEnough), + Ordering::Greater => return Err(FromBytesError::TooLong), + Ordering::Equal => () + }; + + let mut res: Self = unsafe { mem::uninitialized() }; + res.copy_raw(bytes); + Ok(res) + } +} + +impl FromRawBytes for String { + fn from_bytes(bytes: &[u8]) -> Result { + Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) + } +} + +impl FromRawBytes for Vec { + fn from_bytes(bytes: &[u8]) -> Result, FromBytesError> { + Ok(bytes.clone().to_vec()) + } +} + #[test] fn fax_raw() { let mut x = [255u8; 4]; diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 7656a938f..73f2542f4 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -232,7 +232,7 @@ impl KeyFileCrypto { }; Ok(KeyFileCrypto { - cipher_text: Bytes::from(cipher_text), + cipher_text: match FromHex::from_hex(cipher_text) { Ok(bytes) => bytes, Err(_) => { return Err(CryptoParseError::InvalidCipherText); } }, cipher_type: cipher_type, kdf: kdf, mac: mac, diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index f473d0ea2..c72a0a7f3 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -32,14 +32,14 @@ const KEY_LENGTH_AES_USIZE: usize = KEY_LENGTH_AES as usize; /// Encrypted hash-map, each request should contain password pub trait EncryptedHashMap { /// Returns existing value for the key, if any - fn get(&self, key: &Key, password: &str) -> Result; + fn get(&self, key: &Key, password: &str) -> Result; /// Insert new encrypted key-value and returns previous if there was any - fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; + fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; /// Removes key-value by key and returns the removed one, if any exists and password was provided - fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; + fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; /// Deletes key-value by key and returns if the key-value existed fn delete(&mut self, key: &Key) -> bool { - self.remove::<&[u8]>(key, None).is_some() + self.remove::(key, None).is_some() } } @@ -49,7 +49,9 @@ pub enum EncryptedHashMapError { /// Encryption failed InvalidPassword, /// No key in the hashmap - UnknownIdentifier + UnknownIdentifier, + /// Stored value is not well formed for the requested type + InvalidValueFormat(FromBytesError), } /// Represent service for storing encrypted arbitrary data @@ -96,14 +98,16 @@ fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes { } impl EncryptedHashMap for SecretStore { - fn get(&self, key: &H128, password: &str) -> Result { + fn get(&self, key: &H128, password: &str) -> Result { match self.directory.get(key) { Some(key_file) => { let decrypted_bytes = match key_file.crypto.kdf { KeyFileKdf::Pbkdf2(ref params) => { - let (derived_left_bits, derived_right_bits) = derive_key(password, ¶ms.salt); - let expected_mac = derive_mac(&derived_right_bits, &key_file.crypto.cipher_text).sha3(); - if expected_mac != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } + let (derived_left_bits, derived_right_bits) = derive_key_iterations(password, ¶ms.salt, params.c); + //assert_eq!(derive_mac(&derived_right_bits, &key_file.crypto.cipher_text).to_hex(), ""); + assert_eq!(&key_file.crypto.cipher_text.to_hex(), "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46"); + if derive_mac(&derived_right_bits, &key_file.crypto.cipher_text) + .sha3() != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } let mut val = vec![0u8; key_file.crypto.cipher_text.len()]; match key_file.crypto.cipher_type { @@ -116,15 +120,16 @@ impl EncryptedHashMap for SecretStore { _ => { unimplemented!(); } }; - let mut instance = Value::default(); - instance.populate_raw(&decrypted_bytes); - Ok(instance) + match Value::from_bytes(&decrypted_bytes) { + Ok(value) => Ok(value), + Err(bytes_error) => Err(EncryptedHashMapError::InvalidValueFormat(bytes_error)) + } }, None => Err(EncryptedHashMapError::UnknownIdentifier) } } - fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { + fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { let previous = if let Ok(previous_value) = self.get(&key, password) { Some(previous_value) } else { None }; // crypto random initiators @@ -156,7 +161,7 @@ impl EncryptedHashMap for SecretStore { previous } - fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { + fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { let previous = if let Some(pass) = password { if let Ok(previous_value) = self.get(&key, pass) { Some(previous_value) } else { None } } @@ -229,7 +234,7 @@ mod tests { } let sstore = SecretStore::new_test(&temp); if let Ok(_) = sstore.get::(&H128::from_str("3198bc9c66725ab3d9954942343ae5b6").unwrap(), "testpassword") { - panic!("shoud be error loading key, we requested the wrong key"); + panic!("should be error loading key, we requested the wrong key"); } } From 4a028f5faf220812f9e4138c0219a5fd5c8018dc Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 02:49:13 +0300 Subject: [PATCH 061/753] cleanup asserts --- util/src/keys/store.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index c72a0a7f3..b9ee57694 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -104,8 +104,6 @@ impl EncryptedHashMap for SecretStore { let decrypted_bytes = match key_file.crypto.kdf { KeyFileKdf::Pbkdf2(ref params) => { let (derived_left_bits, derived_right_bits) = derive_key_iterations(password, ¶ms.salt, params.c); - //assert_eq!(derive_mac(&derived_right_bits, &key_file.crypto.cipher_text).to_hex(), ""); - assert_eq!(&key_file.crypto.cipher_text.to_hex(), "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46"); if derive_mac(&derived_right_bits, &key_file.crypto.cipher_text) .sha3() != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } From d63f13245f38de879308c1e526114ee9f8abd53d Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 03:17:02 +0300 Subject: [PATCH 062/753] doc typo --- util/src/semantic_version.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/semantic_version.rs b/util/src/semantic_version.rs index 496ff2318..b550cd829 100644 --- a/util/src/semantic_version.rs +++ b/util/src/semantic_version.rs @@ -16,13 +16,13 @@ //! Semantic version formatting and comparing. -/// A version value with strict meaning. Use `to_u32` to convert to a simple integer. -/// +/// A version value with strict meaning. Use `as_u32` to convert to a simple integer. +/// /// # Example /// ``` /// extern crate ethcore_util as util; /// use util::semantic_version::*; -/// +/// /// fn main() { /// assert_eq!(SemanticVersion::new(1, 2, 3).as_u32(), 0x010203); /// } From 39a98cd555dbb48caf1c9ff1632f5ff9993a9170 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Feb 2016 01:39:16 +0100 Subject: [PATCH 063/753] Prevent connection deletion until unregister is called; minor tweaks --- sync/src/chain.rs | 2 +- util/src/network/host.rs | 6 ++---- util/src/network/session.rs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 8f3d7440b..bbfefb78d 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1179,7 +1179,7 @@ impl ChainSync { for (peer_id, peer_number) in updated_peers { let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone(); if best_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber { - // If we think peer is too far behind just end one latest hash + // If we think peer is too far behind just send one latest hash peer_best = last_parent.clone(); } sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &local_best) { diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 9560ca81e..fc4e07306 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -682,14 +682,13 @@ impl Host where Message: Send + Sync + Clone { let mut failure_id = None; match token { FIRST_HANDSHAKE ... LAST_HANDSHAKE => { - let mut handshakes = self.handshakes.write().unwrap(); + let handshakes = self.handshakes.write().unwrap(); if let Some(handshake) = handshakes.get(token).cloned() { failure_id = Some(handshake.lock().unwrap().id().clone()); - handshakes.remove(token); } }, FIRST_SESSION ... LAST_SESSION => { - let mut sessions = self.sessions.write().unwrap(); + let sessions = self.sessions.write().unwrap(); if let Some(session) = sessions.get(token).cloned() { let s = session.lock().unwrap(); if s.is_ready() { @@ -700,7 +699,6 @@ impl Host where Message: Send + Sync + Clone { } } failure_id = Some(s.id().clone()); - sessions.remove(token); } }, _ => {}, diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 04fb6d930..572b91a18 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -91,7 +91,7 @@ impl Decodable for PeerCapabilityInfo { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug)] struct SessionCapabilityInfo { pub protocol: &'static str, pub version: u8, From e4baf37bf87fe29aa9355412a41016ade2897129 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Feb 2016 02:55:46 +0100 Subject: [PATCH 064/753] Fixed adding boot nodes to discovery table; Ping optimization --- util/src/network/discovery.rs | 11 +++++++++-- util/src/network/host.rs | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index f383b74f7..950c66dae 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -149,6 +149,13 @@ impl Discovery { } } + fn clear_ping(&mut self, id: &NodeId) { + let mut bucket = self.node_buckets.get_mut(Discovery::distance(&self.id, &id) as usize).unwrap(); + if let Some(node) = bucket.nodes.iter_mut().find(|n| &n.address.id == id) { + node.timeout = None; + } + } + fn start(&mut self) { trace!(target: "discovery", "Starting discovery"); self.discovery_round = 0; @@ -388,10 +395,10 @@ impl Discovery { debug!(target: "discovery", "Bad address: {:?}", entry); entry.endpoint.address = from.clone(); } - self.update_node(entry.clone()); + self.clear_ping(node); let mut added_map = HashMap::new(); added_map.insert(node.clone(), entry); - Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) + Ok(None) } fn on_find_node(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { diff --git a/util/src/network/host.rs b/util/src/network/host.rs index fc4e07306..e470d47d8 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -374,12 +374,12 @@ impl Host where Message: Send + Sync + Clone { host.info.write().unwrap().deref_mut().listen_port = port; let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); - for n in boot_nodes { - host.add_node(&n); - } if let Some(ref mut discovery) = host.discovery { discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries()); } + for n in boot_nodes { + host.add_node(&n); + } host } From 14b02ff26faf31069e0d6fa807abe1b7fb913934 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 11:48:12 +0300 Subject: [PATCH 065/753] tests and fixes --- util/src/keys/directory.rs | 33 +++++++++++++++++++++++++++++++++ util/src/keys/store.rs | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 73f2542f4..7cc101da1 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -546,6 +546,24 @@ impl KeyDirectory { Ok(()) } + /// Enumerates all keys in the directory + pub fn list(&self) -> Result, ::std::io::Error> { + let mut result = Vec::new(); + for entry in try!(fs::read_dir(&self.path)) { + let entry = try!(entry); + if !try!(fs::metadata(entry.path())).is_dir() { + match entry.file_name().to_str() { + Some(ref name) => { + if let Ok(uuid) = uuid_from_string(name) { result.push(uuid); } + }, + None => { continue; } + }; + + } + } + Ok(result) + } + fn key_path(&self, id: &Uuid) -> PathBuf { let mut path = PathBuf::new(); path.push(self.path.clone()); @@ -1130,4 +1148,19 @@ mod specs { assert_eq!(10, keys.len()) } + + #[test] + fn can_list_keys() { + let temp_path = RandomTempPath::create_dir(); + let mut directory = KeyDirectory::new(&temp_path.as_path()); + + let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); + let mut keys = Vec::new(); + for _ in 0..33 { + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); + keys.push(directory.save(key).unwrap()); + } + + assert_eq!(33, directory.list().unwrap().len()); + } } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index b9ee57694..e122ce808 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -145,7 +145,7 @@ impl EncryptedHashMap for SecretStore { // KECCAK(DK[16..31] ++ ), where DK[16..31] - derived_right_bits let mac = derive_mac(&derived_right_bits, &cipher_text.clone()).sha3(); - let key_file = KeyFileContent::new( + let mut key_file = KeyFileContent::new( KeyFileCrypto::new_pbkdf2( cipher_text, iv, @@ -153,6 +153,7 @@ impl EncryptedHashMap for SecretStore { mac, KEY_ITERATIONS, KEY_LENGTH)); + key_file.id = key; if let Err(io_error) = self.directory.save(key_file) { warn!("Error saving key file: {:?}", io_error); } @@ -210,7 +211,10 @@ mod tests { let temp = RandomTempPath::create_dir(); let mut sstore = SecretStore::new_test(&temp); - sstore.insert(H128::random(), "Cat".to_owned(), "pass"); + let id = H128::random(); + sstore.insert(id.clone(), "Cat".to_owned(), "pass"); + + assert!(sstore.get::(&id, "pass").is_ok()); } #[test] @@ -236,6 +240,25 @@ mod tests { } } + fn pregenerate_keys(temp: &RandomTempPath, count: usize) -> Vec { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + let mut result = Vec::new(); + for _ in 0..count { + result.push(write_sstore.directory.save( + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32))) + .unwrap()); + } + result + } + #[test] fn secret_store_get() { let temp = RandomTempPath::create_dir(); @@ -259,5 +282,16 @@ mod tests { } } + #[test] + fn secret_store_delete() { + let temp = RandomTempPath::create_dir(); + let keys = pregenerate_keys(&temp, 5); + + let mut sstore = SecretStore::new_test(&temp); + sstore.delete(&keys[2]); + + assert_eq!(4, sstore.directory.list().unwrap().len()) + } + } From ca99679d1d009e8aad83cd4e0335cfef635724dc Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 11:57:13 +0300 Subject: [PATCH 066/753] fixed test names --- idea | 105 +++++++++++++++++++++++++++++++++++++++++ util/src/keys/store.rs | 8 ++-- 2 files changed, 109 insertions(+), 4 deletions(-) create mode 100755 idea diff --git a/idea b/idea new file mode 100755 index 000000000..c3e170967 --- /dev/null +++ b/idea @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import socket +import struct +import sys +import os +import time + +# see com.intellij.idea.SocketLock for the server side of this interface + +RUN_PATH = u'/home/nikvolf/idea/bin/idea.sh' +CONFIG_PATH = u'/home/nikvolf/.IdeaIC15/config' + +args = [] +skip_next = False +for i, arg in enumerate(sys.argv[1:]): + if arg == '-h' or arg == '-?' or arg == '--help': + print(('Usage:\n' + + ' {0} -h |-? | --help\n' + + ' {0} [-l|--line line] file[:line]\n' + + ' {0} diff ' + + ' {0} merge [base] ').format(sys.argv[0])) + exit(0) + elif arg == 'diff' and i == 0: + args.append(arg) + elif arg == 'merge' and i == 0: + args.append(arg) + elif arg == '-l' or arg == '--line': + args.append(arg) + skip_next = True + elif skip_next: + args.append(arg) + skip_next = False + else: + if ':' in arg: + file_path, line_number = arg.rsplit(':', 1) + if line_number.isdigit(): + args.append('-l') + args.append(line_number) + args.append(os.path.abspath(file_path)) + else: + args.append(os.path.abspath(arg)) + else: + args.append(os.path.abspath(arg)) + + +def launch_with_port(port): + found = False + + s = socket.socket() + s.settimeout(0.3) + try: + s.connect(('127.0.0.1', port)) + except: + return False + + while True: + try: + path_len = struct.unpack(">h", s.recv(2))[0] + path = s.recv(path_len) + if os.path.abspath(path) == os.path.abspath(CONFIG_PATH): + found = True + break + except: + break + + if found: + if args: + cmd = "activate " + os.getcwd() + "\0" + "\0".join(args) + encoded = struct.pack(">h", len(cmd)) + cmd + s.send(encoded) + time.sleep(0.5) # don't close socket immediately + return True + + return False + + +port = -1 +try: + f = open(os.path.join(CONFIG_PATH, 'port')) + port = int(f.read()) +except Exception: + type, value, traceback = sys.exc_info() + print('No IDE instance has been found. New one will be started.') + port = -1 + +if port == -1: + # SocketLock actually allows up to 50 ports, but the checking takes too long + for port in range(6942, 6942 + 10): + if launch_with_port(port): + exit() +else: + if launch_with_port(port): + exit() + +if sys.platform == "darwin": + # OS X: RUN_PATH is *.app path + if len(args): + args.insert(0, "--args") + os.execvp("open", ["-a", RUN_PATH] + args) +else: + # unix common + bin_dir, bin_file = os.path.split(RUN_PATH) + os.execv(RUN_PATH, [bin_file] + args) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index e122ce808..b8b0b0a47 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -207,7 +207,7 @@ mod tests { use common::*; #[test] - fn secret_store_insert() { + fn can_insert() { let temp = RandomTempPath::create_dir(); let mut sstore = SecretStore::new_test(&temp); @@ -218,7 +218,7 @@ mod tests { } #[test] - fn secret_store_get_fail() { + fn can_get_fail() { let temp = RandomTempPath::create_dir(); { use keys::directory::{KeyFileContent, KeyFileCrypto}; @@ -260,7 +260,7 @@ mod tests { } #[test] - fn secret_store_get() { + fn can_get() { let temp = RandomTempPath::create_dir(); let key_id = { use keys::directory::{KeyFileContent, KeyFileCrypto}; @@ -283,7 +283,7 @@ mod tests { } #[test] - fn secret_store_delete() { + fn can_delete() { let temp = RandomTempPath::create_dir(); let keys = pregenerate_keys(&temp, 5); From 40f5ea400729e6cbbe3e596f8007e6f2c7593b4a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 11:59:14 +0300 Subject: [PATCH 067/753] removed idea trash --- idea | 105 ----------------------------------------------------------- 1 file changed, 105 deletions(-) delete mode 100755 idea diff --git a/idea b/idea deleted file mode 100755 index c3e170967..000000000 --- a/idea +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import socket -import struct -import sys -import os -import time - -# see com.intellij.idea.SocketLock for the server side of this interface - -RUN_PATH = u'/home/nikvolf/idea/bin/idea.sh' -CONFIG_PATH = u'/home/nikvolf/.IdeaIC15/config' - -args = [] -skip_next = False -for i, arg in enumerate(sys.argv[1:]): - if arg == '-h' or arg == '-?' or arg == '--help': - print(('Usage:\n' + - ' {0} -h |-? | --help\n' + - ' {0} [-l|--line line] file[:line]\n' + - ' {0} diff ' + - ' {0} merge [base] ').format(sys.argv[0])) - exit(0) - elif arg == 'diff' and i == 0: - args.append(arg) - elif arg == 'merge' and i == 0: - args.append(arg) - elif arg == '-l' or arg == '--line': - args.append(arg) - skip_next = True - elif skip_next: - args.append(arg) - skip_next = False - else: - if ':' in arg: - file_path, line_number = arg.rsplit(':', 1) - if line_number.isdigit(): - args.append('-l') - args.append(line_number) - args.append(os.path.abspath(file_path)) - else: - args.append(os.path.abspath(arg)) - else: - args.append(os.path.abspath(arg)) - - -def launch_with_port(port): - found = False - - s = socket.socket() - s.settimeout(0.3) - try: - s.connect(('127.0.0.1', port)) - except: - return False - - while True: - try: - path_len = struct.unpack(">h", s.recv(2))[0] - path = s.recv(path_len) - if os.path.abspath(path) == os.path.abspath(CONFIG_PATH): - found = True - break - except: - break - - if found: - if args: - cmd = "activate " + os.getcwd() + "\0" + "\0".join(args) - encoded = struct.pack(">h", len(cmd)) + cmd - s.send(encoded) - time.sleep(0.5) # don't close socket immediately - return True - - return False - - -port = -1 -try: - f = open(os.path.join(CONFIG_PATH, 'port')) - port = int(f.read()) -except Exception: - type, value, traceback = sys.exc_info() - print('No IDE instance has been found. New one will be started.') - port = -1 - -if port == -1: - # SocketLock actually allows up to 50 ports, but the checking takes too long - for port in range(6942, 6942 + 10): - if launch_with_port(port): - exit() -else: - if launch_with_port(port): - exit() - -if sys.platform == "darwin": - # OS X: RUN_PATH is *.app path - if len(args): - args.insert(0, "--args") - os.execvp("open", ["-a", RUN_PATH] + args) -else: - # unix common - bin_dir, bin_file = os.path.split(RUN_PATH) - os.execv(RUN_PATH, [bin_file] + args) From 5826a34ebb28cc914cf568d9a23995550ec95c43 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 17 Feb 2016 12:35:37 +0100 Subject: [PATCH 068/753] storing block receitps in db, client logs method implementation --- ethcore/src/blockchain.rs | 49 ++++++++++++++---------- ethcore/src/client.rs | 53 +++++++++++++++++++++++++- ethcore/src/extras.rs | 47 ++++++++++++++++++++++- ethcore/src/filter.rs | 72 ++++++++++++++++++++++++++++++++++-- ethcore/src/log_entry.rs | 18 +++++++++ ethcore/src/receipt.rs | 18 +++++++++ ethcore/src/tests/helpers.rs | 4 +- ethcore/src/verification.rs | 4 ++ 8 files changed, 236 insertions(+), 29 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 1a329610c..052e64d4c 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -50,7 +50,9 @@ pub struct CacheSize { /// Logs cache size. pub block_logs: usize, /// Blooms cache size. - pub blocks_blooms: usize + pub blocks_blooms: usize, + /// Block receipts size. + pub block_receipts: usize } struct BloomIndexer { @@ -147,6 +149,9 @@ pub trait BlockProvider { /// Get the address of transaction with given hash. fn transaction_address(&self, hash: &H256) -> Option; + /// Get receipts of block with given hash. + fn block_receipts(&self, hash: &H256) -> Option; + /// Get the partial-header of a block. fn block_header(&self, hash: &H256) -> Option
{ self.block(hash).map(|bytes| BlockView::new(&bytes).header()) @@ -223,6 +228,7 @@ pub struct BlockChain { transaction_addresses: RwLock>, block_logs: RwLock>, blocks_blooms: RwLock>, + block_receipts: RwLock>, extras_db: DB, blocks_db: DB, @@ -287,6 +293,11 @@ impl BlockProvider for BlockChain { self.query_extras(hash, &self.transaction_addresses) } + /// Get receipts of block with given hash. + fn block_receipts(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.block_receipts) + } + /// Returns numbers of blocks containing given bloom. fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { let filter = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()); @@ -348,6 +359,7 @@ impl BlockChain { transaction_addresses: RwLock::new(HashMap::new()), block_logs: RwLock::new(HashMap::new()), blocks_blooms: RwLock::new(HashMap::new()), + block_receipts: RwLock::new(HashMap::new()), extras_db: extras_db, blocks_db: blocks_db, cache_man: RwLock::new(cache_man), @@ -504,7 +516,7 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, bytes: &[u8], receipts: &[Receipt]) { + pub fn insert_block(&self, bytes: &[u8], receipts: Vec) { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -546,8 +558,7 @@ impl BlockChain { /// Transforms block into WriteBatch that may be written into database /// Additionally, if it's new best block it returns new best block object. - //fn block_to_extras_insert_batch(&self, bytes: &[u8], _receipts: &[Receipt]) -> (WriteBatch, Option, BlockDetails) { - fn block_to_extras_update(&self, bytes: &[u8], _receipts: &[Receipt]) -> ExtrasUpdate { + fn block_to_extras_update(&self, bytes: &[u8], receipts: Vec) -> ExtrasUpdate { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -585,11 +596,8 @@ impl BlockChain { }); } - // save blooms (is it really required?). maybe store receipt whole instead? - //let blooms: Vec = receipts.iter().map(|r| r.log_bloom.clone()).collect(); - //batch.put_extras(&hash, &BlockLogBlooms { - //blooms: blooms - //}); + // update block receipts + batch.put_extras(&hash, &BlockReceipts::new(receipts)); // if it's not new best block, just return if !is_new_best { @@ -741,7 +749,8 @@ impl BlockChain { block_details: self.block_details.read().unwrap().heap_size_of_children(), transaction_addresses: self.transaction_addresses.read().unwrap().heap_size_of_children(), block_logs: self.block_logs.read().unwrap().heap_size_of_children(), - blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children() + blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children(), + block_receipts: self.block_receipts.read().unwrap().heap_size_of_children() } } @@ -773,6 +782,7 @@ impl BlockChain { let mut transaction_addresses = self.transaction_addresses.write().unwrap(); let mut block_logs = self.block_logs.write().unwrap(); let mut blocks_blooms = self.blocks_blooms.write().unwrap(); + let mut block_receipts = self.block_receipts.write().unwrap(); for id in cache_man.cache_usage.pop_back().unwrap().into_iter() { cache_man.in_use.remove(&id); @@ -782,6 +792,7 @@ impl BlockChain { CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); }, CacheID::Extras(ExtrasIndex::BlockLogBlooms, h) => { block_logs.remove(&h); }, CacheID::Extras(ExtrasIndex::BlocksBlooms, h) => { blocks_blooms.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlockReceipts, h) => { block_receipts.remove(&h); }, _ => panic!(), } } @@ -823,7 +834,7 @@ mod tests { let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); - bc.insert_block(&first, &[]); + bc.insert_block(&first, vec![]); let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap(); @@ -856,10 +867,10 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); - bc.insert_block(&b1, &[]); - bc.insert_block(&b2, &[]); - bc.insert_block(&b3a, &[]); - bc.insert_block(&b3b, &[]); + bc.insert_block(&b1, vec![]); + bc.insert_block(&b2, vec![]); + bc.insert_block(&b3a, vec![]); + bc.insert_block(&b3b, vec![]); assert_eq!(bc.best_block_hash(), best_block_hash); assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0); @@ -936,7 +947,7 @@ mod tests { { let bc = BlockChain::new(&genesis, temp.as_path()); assert_eq!(bc.best_block_hash(), genesis_hash); - bc.insert_block(&b1, &[]); + bc.insert_block(&b1, vec![]); assert_eq!(bc.best_block_hash(), b1_hash); } @@ -995,7 +1006,7 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); - bc.insert_block(&b1, &[]); + bc.insert_block(&b1, vec![]); let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); @@ -1026,13 +1037,13 @@ mod tests { assert_eq!(blocks_b1, vec![]); assert_eq!(blocks_b2, vec![]); - bc.insert_block(&b1, &[]); + bc.insert_block(&b1, vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![]); - bc.insert_block(&b2, &[]); + bc.insert_block(&b2, vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); assert_eq!(blocks_b1, vec![1]); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index d7fcdbc30..7fe3fe836 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -33,7 +33,9 @@ use env_info::LastHashes; use verification::*; use block::*; use transaction::LocalizedTransaction; -use extras::TransactionAddress; +use extras::{TransactionAddress, BlockReceipts}; +use filter::Filter; +use log_entry::LocalizedLogEntry; pub use blockchain::TreeRoute; /// Uniquely identifies block. @@ -147,6 +149,9 @@ pub trait BlockChainClient : Sync + Send { /// Returns numbers of blocks containing given bloom. fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option>; + + /// Returns logs matching given filter. + fn logs(&self, filter: Filter) -> Vec; } #[derive(Default, Clone, Debug, Eq, PartialEq)] @@ -307,7 +312,7 @@ impl Client { good_blocks.push(header.hash().clone()); - self.chain.write().unwrap().insert_block(&block.bytes, result.block().receipts()); //TODO: err here? + self.chain.write().unwrap().insert_block(&block.bytes, result.block().receipts().clone()); //TODO: err here? let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { Ok(_) => (), @@ -474,6 +479,50 @@ impl BlockChainClient for Client { _ => None } } + + fn logs(&self, filter: Filter) -> Vec { + let mut blocks = filter.bloom_possibilities().iter() + .map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone())) + .filter_map(|m| m) + .flat_map(|m| m) + // remove duplicate elements + .collect::>() + .into_iter() + .collect::>(); + + blocks.sort(); + + blocks.into_iter() + .map(|number| self.chain.read().unwrap().block_hash(number).map(|hash| (number, hash))) + .filter_map(|m| m) + .map(|(number, hash)| self.chain.read().unwrap().block_receipts(&hash).map(|r| (number, hash, r.receipts))) + .filter_map(|m| m) + .map(|(number, hash, receipts)| { + let mut log_index = 0; + receipts.into_iter() + .enumerate() + .map(|(index, receipt)| { + log_index += receipt.logs.len(); + receipt.logs.into_iter() + .enumerate() + .filter(|tuple| filter.matches(&tuple.1)) + .map(|(i, log)| LocalizedLogEntry { + entry: log, + block_hash: hash.clone(), + block_number: number as usize, + transaction_hash: H256::new(), + transaction_index: index, + log_index: log_index + }) + .collect::>() + }) + .flat_map(|m| m) + .collect::>() + + }) + .flat_map(|m| m) + .collect() + } } impl MayPanic for Client { diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index 66e734582..50d3a21bf 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -16,9 +16,10 @@ //! Blockchain DB extras. +use rocksdb::{DB, Writable}; use util::*; use header::BlockNumber; -use rocksdb::{DB, Writable}; +use receipt::Receipt; /// Represents index of extra data in database #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] @@ -32,7 +33,9 @@ pub enum ExtrasIndex { /// Block log blooms index BlockLogBlooms = 3, /// Block blooms index - BlocksBlooms = 4 + BlocksBlooms = 4, + /// Block receipts index + BlockReceipts } /// trait used to write Extras data to db @@ -307,3 +310,43 @@ impl Encodable for TransactionAddress { s.append(&self.index); } } + +/// Contains all block receipts. +#[derive(Clone)] +pub struct BlockReceipts { + pub receipts: Vec +} + +impl BlockReceipts { + pub fn new(receipts: Vec) -> Self { + BlockReceipts { + receipts: receipts + } + } +} + +impl Decodable for BlockReceipts { + fn decode(decoder: &D) -> Result where D: Decoder { + Ok(BlockReceipts { + receipts: try!(Decodable::decode(decoder)) + }) + } +} + +impl Encodable for BlockReceipts { + fn rlp_append(&self, s: &mut RlpStream) { + s.append(&self.receipts); + } +} + +impl HeapSizeOf for BlockReceipts { + fn heap_size_of_children(&self) -> usize { + self.receipts.heap_size_of_children() + } +} + +impl ExtrasIndexable for BlockReceipts { + fn extras_index() -> ExtrasIndex { + ExtrasIndex::BlockReceipts + } +} diff --git a/ethcore/src/filter.rs b/ethcore/src/filter.rs index 718656191..89295b9c2 100644 --- a/ethcore/src/filter.rs +++ b/ethcore/src/filter.rs @@ -17,26 +17,27 @@ use util::hash::*; use util::sha3::*; use client::BlockId; +use log_entry::LogEntry; /// Blockchain log filter data. pub struct Filter { /// Blockchain will be searched from this block. - from_block: BlockId, + pub from_block: BlockId, /// Till this block. - to_block: BlockId, + pub to_block: BlockId, /// Search addresses. /// /// If None, match all. /// If specified, log must be produced by one of these addresses. - address: Option>, + pub address: Option>, /// Search topics. /// /// If None, match all. /// If specified, log must contain one of these topics. - topics: [Option>; 4] + pub topics: [Option>; 4] } impl Filter { @@ -63,6 +64,23 @@ impl Filter { }).flat_map(|m| m).collect() }) } + + /// Returns true if given log entry matches filter. + pub fn matches(&self, log: &LogEntry) -> bool { + let matches = match self.address { + Some(ref addresses) if !addresses.is_empty() => addresses.iter().fold(false, |res, address| { + res || &log.address == address + }), + _ => true + }; + + matches && self.topics.iter().enumerate().fold(true, |res, (i, topic)| match *topic { + Some(ref topics) if !topics.is_empty() => res && topics.iter().fold(false, | acc, topic | { + acc || log.topics.get(i) == Some(topic) + }), + _ => res, + }) + } } #[cfg(test)] @@ -71,6 +89,7 @@ mod tests { use util::hash::*; use filter::Filter; use client::BlockId; + use log_entry::LogEntry; #[test] fn test_bloom_possibilities_none() { @@ -149,4 +168,49 @@ mod tests { assert_eq!(possibilities[0], H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()); } + #[test] + fn test_filter_matches() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), + topics: [ + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap()]), + None, None + ] + }; + + let entry0 = LogEntry { + address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + topics: vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + ], + data: vec![] + }; + + let entry1 = LogEntry { + address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5e").unwrap(), + topics: vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + ], + data: vec![] + }; + + let entry2 = LogEntry { + address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + topics: vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + ], + data: vec![] + }; + + assert_eq!(filter.matches(&entry0), true); + assert_eq!(filter.matches(&entry1), false); + assert_eq!(filter.matches(&entry2), false); + } } diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index 304fae9d0..24f449dce 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -37,6 +37,24 @@ impl Encodable for LogEntry { } } +impl Decodable for LogEntry { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + let entry = LogEntry { + address: try!(d.val_at(0)), + topics: try!(d.val_at(1)), + data: try!(d.val_at(2)), + }; + Ok(entry) + } +} + +impl HeapSizeOf for LogEntry { + fn heap_size_of_children(&self) -> usize { + self.topics.heap_size_of_children() + self.data.heap_size_of_children() + } +} + impl LogEntry { /// Calculates the bloom of this log entry. pub fn bloom(&self) -> LogBloom { diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index f43b58224..1ec52c592 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -55,6 +55,24 @@ impl Encodable for Receipt { } } +impl Decodable for Receipt { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + let receipt = Receipt { + state_root: try!(d.val_at(0)), + gas_used: try!(d.val_at(1)), + log_bloom: try!(d.val_at(2)), + logs: try!(d.val_at(3)), + }; + Ok(receipt) + } +} + +impl HeapSizeOf for Receipt { + fn heap_size_of_children(&self) -> usize { + self.logs.heap_size_of_children() + } +} #[test] fn test_basic() { diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 0a2b95e8d..38cd48f32 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -224,7 +224,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult { @@ -237,7 +237,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes let temp = RandomTempPath::new(); let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); for block_order in 1..block_number { - bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), &[]); + bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![]); } GuardedTempResult:: { diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index 548150f09..ad5efd24a 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -306,6 +306,10 @@ mod tests { fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec { unimplemented!() } + + fn block_receipts(&self, _hash: &H256) -> Option { + unimplemented!() + } } fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> { From eef193e8bd377b1d9483b814a2999980b5bfb613 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Feb 2016 14:06:19 +0100 Subject: [PATCH 069/753] Don't add useless peers to table --- util/src/network/discovery.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 950c66dae..b12e3b2a1 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -361,24 +361,21 @@ impl Discovery { debug!(target: "discovery", "Expired ping"); return Err(NetworkError::Expired); } - let mut entry = NodeEntry { id: node.clone(), endpoint: source.clone() }; - if !entry.endpoint.is_valid() { - debug!(target: "discovery", "Got bad address: {:?}, using {:?} instead", entry, from); - entry.endpoint.address = from.clone(); + let mut added_map = HashMap::new(); + let entry = NodeEntry { id: node.clone(), endpoint: source.clone() }; + if !entry.endpoint.is_valid() || !entry.endpoint.is_global() { + debug!(target: "discovery", "Got bad address: {:?}", entry); } - if !entry.endpoint.is_global() { - debug!(target: "discovery", "Got local address: {:?}, using {:?} instead", entry, from); - entry.endpoint.address = from.clone(); + else { + self.update_node(entry.clone()); + added_map.insert(node.clone(), entry); } - self.update_node(entry.clone()); let hash = rlp.as_raw().sha3(); let mut response = RlpStream::new_list(2); dest.to_rlp_list(&mut response); response.append(&hash); - self.send_packet(PACKET_PONG, &entry.endpoint.udp_address(), &response.drain()); + self.send_packet(PACKET_PONG, from, &response.drain()); - let mut added_map = HashMap::new(); - added_map.insert(node.clone(), entry); Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) } From c9f3f5e54482e592fb8e36e149dd596b46078efe Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Feb 2016 14:07:11 +0100 Subject: [PATCH 070/753] Tweaked connection limits to be a bit more aggressive --- util/src/network/handshake.rs | 2 +- util/src/network/host.rs | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 1fd830ea0..5d43decd7 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -68,7 +68,7 @@ pub struct Handshake { const AUTH_PACKET_SIZE: usize = 307; const ACK_PACKET_SIZE: usize = 210; -const HANDSHAKE_TIMEOUT: u64 = 30000; +const HANDSHAKE_TIMEOUT: u64 = 5000; impl Handshake { /// Create a new handshake object diff --git a/util/src/network/host.rs b/util/src/network/host.rs index e470d47d8..460cabc7c 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -46,8 +46,8 @@ type Slab = ::slab::Slab; const _DEFAULT_PORT: u16 = 30304; const MAX_SESSIONS: usize = 1024; -const MAX_HANDSHAKES: usize = 64; -const MAX_HANDSHAKES_PER_ROUND: usize = 8; +const MAX_HANDSHAKES: usize = 80; +const MAX_HANDSHAKES_PER_ROUND: usize = 32; const MAINTENANCE_TIMEOUT: u64 = 1000; #[derive(Debug)] @@ -977,3 +977,13 @@ fn key_save_load() { let r = load_key(temp_path.as_path()); assert_eq!(key, r.unwrap()); } + + +#[test] +fn host_client_url() { + let mut config = NetworkConfiguration::new(); + let key = h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2"); + config.use_secret = Some(key); + let host: Host = Host::new(config); + assert!(host.client_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); +} From 0cfc4cbb3437d9547fc78e85ef5e5b08f08490fb Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Feb 2016 14:07:26 +0100 Subject: [PATCH 071/753] More tests --- util/src/network/error.rs | 60 ++++++++++++++++++++++++++++++------- util/src/network/session.rs | 6 +++- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/util/src/network/error.rs b/util/src/network/error.rs index 74babb110..31e1d785b 100644 --- a/util/src/network/error.rs +++ b/util/src/network/error.rs @@ -18,21 +18,42 @@ use io::IoError; use crypto::CryptoError; use rlp::*; -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum DisconnectReason { DisconnectRequested, - _TCPError, - _BadProtocol, + TCPError, + BadProtocol, UselessPeer, - _TooManyPeers, - _DuplicatePeer, - _IncompatibleProtocol, - _NullIdentity, - _ClientQuit, - _UnexpectedIdentity, - _LocalIdentity, + TooManyPeers, + DuplicatePeer, + IncompatibleProtocol, + NullIdentity, + ClientQuit, + UnexpectedIdentity, + LocalIdentity, PingTimeout, + Unknown, +} + +impl DisconnectReason { + pub fn from_u8(n: u8) -> DisconnectReason { + match n { + 0 => DisconnectReason::DisconnectRequested, + 1 => DisconnectReason::TCPError, + 2 => DisconnectReason::BadProtocol, + 3 => DisconnectReason::UselessPeer, + 4 => DisconnectReason::TooManyPeers, + 5 => DisconnectReason::DuplicatePeer, + 6 => DisconnectReason::IncompatibleProtocol, + 7 => DisconnectReason::NullIdentity, + 8 => DisconnectReason::ClientQuit, + 9 => DisconnectReason::UnexpectedIdentity, + 10 => DisconnectReason::LocalIdentity, + 11 => DisconnectReason::PingTimeout, + _ => DisconnectReason::Unknown, + } + } } #[derive(Debug)] @@ -70,3 +91,22 @@ impl From for NetworkError { } } +#[test] +fn test_errors() { + assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8)); + let mut r = DisconnectReason::DisconnectRequested; + for i in 0 .. 20 { + r = DisconnectReason::from_u8(i); + } + assert_eq!(DisconnectReason::Unknown, r); + + match >::from(DecoderError::RlpIsTooBig) { + NetworkError::Auth => {}, + _ => panic!("Unexpeceted error"), + } + + match >::from(CryptoError::InvalidSecret) { + NetworkError::Auth => {}, + _ => panic!("Unexpeceted error"), + } +} diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 572b91a18..b0db5f7ef 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -231,7 +231,11 @@ impl Session { try!(self.read_hello(&rlp, host)); Ok(SessionData::Ready) }, - PACKET_DISCONNECT => Err(From::from(NetworkError::Disconnect(DisconnectReason::DisconnectRequested))), + PACKET_DISCONNECT => { + let rlp = UntrustedRlp::new(&packet.data[1..]); + let reason: u8 = try!(rlp.val_at(0)); + Err(From::from(NetworkError::Disconnect(DisconnectReason::from_u8(reason)))) + } PACKET_PING => { try!(self.send_pong()); Ok(SessionData::None) From c74c016ce2c175651b82f1fd53bced81a4b8b904 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 17 Feb 2016 14:13:51 +0100 Subject: [PATCH 072/753] moved filter logic from rpc module to ethcore --- ethcore/src/client.rs | 4 +- ethcore/src/filter.rs | 4 +- ethcore/src/lib.rs | 4 +- ethcore/src/log_entry.rs | 2 + rpc/src/v1/impls/eth.rs | 18 ++---- rpc/src/v1/types/filter.rs | 127 ++++++------------------------------- rpc/src/v1/types/log.rs | 52 +++++++++++++++ rpc/src/v1/types/mod.rs | 2 + 8 files changed, 88 insertions(+), 125 deletions(-) create mode 100644 rpc/src/v1/types/log.rs diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 7fe3fe836..ba3c97422 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -33,7 +33,7 @@ use env_info::LastHashes; use verification::*; use block::*; use transaction::LocalizedTransaction; -use extras::{TransactionAddress, BlockReceipts}; +use extras::TransactionAddress; use filter::Filter; use log_entry::LocalizedLogEntry; pub use blockchain::TreeRoute; @@ -512,7 +512,7 @@ impl BlockChainClient for Client { block_number: number as usize, transaction_hash: H256::new(), transaction_index: index, - log_index: log_index + log_index: log_index + i }) .collect::>() }) diff --git a/ethcore/src/filter.rs b/ethcore/src/filter.rs index 89295b9c2..5daecebd3 100644 --- a/ethcore/src/filter.rs +++ b/ethcore/src/filter.rs @@ -14,12 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Blockchain filter + use util::hash::*; use util::sha3::*; use client::BlockId; use log_entry::LogEntry; -/// Blockchain log filter data. +/// Blockchain Filter. pub struct Filter { /// Blockchain will be searched from this block. pub from_block: BlockId, diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 38f961d10..ab3378d7f 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -102,8 +102,10 @@ pub mod block_queue; pub mod client; pub mod error; pub mod ethereum; +pub mod filter; pub mod header; pub mod service; +pub mod log_entry; pub mod spec; pub mod transaction; pub mod views; @@ -112,7 +114,6 @@ pub mod receipt; mod common; mod basic_types; #[macro_use] mod evm; -mod log_entry; mod env_info; mod pod_account; mod pod_state; @@ -131,7 +132,6 @@ mod substate; mod executive; mod externalities; mod verification; -mod filter; #[cfg(test)] mod tests; diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index 24f449dce..a7d409833 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Block log. + use util::*; use basic_types::LogBloom; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index bbeb475dc..42e58493a 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,7 +15,6 @@ // along with Parity. If not, see . //! Eth rpc implementation. -use std::collections::HashSet; use std::sync::Arc; use ethsync::{EthSync, SyncState}; use jsonrpc_core::*; @@ -26,7 +25,7 @@ use ethcore::client::*; use ethcore::views::*; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; /// Eth rpc implementation. pub struct EthClient { @@ -202,18 +201,11 @@ impl Eth for EthClient { fn logs(&self, params: Params) -> Result { from_params::<(Filter,)>(params) .and_then(|(filter,)| { - let possibilities = filter.bloom_possibilities(); - let from = filter.from_block.map_or_else(|| BlockId::Earliest, Into::into); - let to = filter.to_block.map_or_else(|| BlockId::Latest, Into::into); - let mut blocks: Vec = possibilities.iter() - .map(|bloom| self.client.blocks_with_bloom(bloom, from.clone(), to.clone())) - .filter_map(|m| m) - .flat_map(|m| m) - .collect::>() + let logs = self.client.logs(filter.into()) .into_iter() - .collect(); - blocks.sort(); - to_value(&blocks) + .map(From::from) + .collect::>(); + to_value(&logs) }) } } diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index 62b865bee..bb932f349 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -18,8 +18,9 @@ use serde::{Deserialize, Deserializer, Error}; use serde_json::value; use jsonrpc_core::Value; use util::hash::*; -use util::sha3::*; use v1::types::BlockNumber; +use ethcore::filter::Filter as EthFilter; +use ethcore::client::BlockId; #[derive(Debug, PartialEq)] pub enum VariadicValue where T: Deserialize { @@ -56,41 +57,24 @@ pub struct Filter { pub topics: Option> } -impl Filter { - /// Returns combinations of each address and topic. - pub fn bloom_possibilities(&self) -> Vec { - let blooms = match self.address { - Some(VariadicValue::Single(ref address)) => { - let mut bloom = H2048::new(); - bloom.shift_bloomed(&address.sha3()); - vec![bloom] - }, - Some(VariadicValue::Multiple(ref addresses)) => { - addresses.iter().map(|ref address| { - let mut bloom = H2048::new(); - bloom.shift_bloomed(&address.sha3()); - bloom - }).collect() - }, - _ => vec![H2048::new()] - }; - - match self.topics { - None => blooms, - Some(ref topics) => topics.iter().fold(blooms, | bs, topic | match *topic { - VariadicValue::Null => bs, - VariadicValue::Single(ref topic) => bs.into_iter().map(|mut bloom| { - bloom.shift_bloomed(&topic.sha3()); - bloom - }).collect(), - VariadicValue::Multiple(ref topics) => bs.into_iter().map(|bloom| { - topics.into_iter().map(|topic| { - let mut b = bloom.clone(); - b.shift_bloomed(&topic.sha3()); - b - }).collect::>() - }).flat_map(|m| m).collect::>() - }) +impl Into for Filter { + fn into(self) -> EthFilter { + EthFilter { + from_block: self.from_block.map_or_else(|| BlockId::Earliest, Into::into), + to_block: self.to_block.map_or_else(|| BlockId::Latest, Into::into), + address: self.address.and_then(|address| match address { + VariadicValue::Null => None, + VariadicValue::Single(a) => Some(vec![a]), + VariadicValue::Multiple(a) => Some(a) + }), + topics: { + let mut iter = self.topics.map_or_else(Vec::new, |topics| topics.into_iter().take(4).map(|topic| match topic { + VariadicValue::Null => None, + VariadicValue::Single(t) => Some(vec![t]), + VariadicValue::Multiple(t) => Some(t) + }).filter_map(|m| m).collect()).into_iter(); + [iter.next(), iter.next(), iter.next(), iter.next()] + } } } } @@ -128,75 +112,4 @@ mod tests { topics: None }); } - - #[test] - fn test_bloom_possibilities_none() { - let none_filter = Filter { - from_block: None, - to_block: None, - address: None, - topics: None - }; - - let possibilities = none_filter.bloom_possibilities(); - assert_eq!(possibilities, vec![H2048::new()]); - } - - // block 399849 - #[test] - fn test_bloom_possibilities_single_address_and_topic() { - let filter = Filter { - from_block: None, - to_block: None, - address: Some(VariadicValue::Single(Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap())), - topics: Some(vec![VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap())]) - }; - - let possibilities = filter.bloom_possibilities(); - assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); - } - - #[test] - fn test_bloom_possibilities_single_address_and_many_topics() { - let filter = Filter { - from_block: None, - to_block: None, - address: Some(VariadicValue::Single(Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap())), - topics: Some(vec![ - VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()), - VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()) - ]) - }; - - let possibilities = filter.bloom_possibilities(); - assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); - } - - #[test] - fn test_bloom_possibilites_multiple_addresses_and_topics() { - let filter = Filter { - from_block: None, - to_block: None, - address: Some(VariadicValue::Multiple(vec![ - Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), - Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap() - ])), - topics: Some(vec![ - VariadicValue::Multiple(vec![ - H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), - H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() - ]), - VariadicValue::Multiple(vec![ - H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), - H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() - ]), - VariadicValue::Single(H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()) - ]) - }; - - // number of possibilites should be equal 2 * 2 * 2 * 1 = 8 - let possibilities = filter.bloom_possibilities(); - assert_eq!(possibilities.len(), 8); - assert_eq!(possibilities[0], H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()); - } } diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs new file mode 100644 index 000000000..4b8661075 --- /dev/null +++ b/rpc/src/v1/types/log.rs @@ -0,0 +1,52 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::hash::*; +use util::uint::*; +use ethcore::log_entry::LocalizedLogEntry; +use v1::types::Bytes; + +#[derive(Debug, Serialize)] +pub struct Log { + address: Address, + topics: Vec, + data: Bytes, + #[serde(rename="blockHash")] + block_hash: H256, + #[serde(rename="blockNumber")] + block_number: U256, + #[serde(rename="transactionHash")] + transaction_hash: H256, + #[serde(rename="transactionIndex")] + transaction_index: U256, + #[serde(rename="logIndex")] + log_index: U256 +} + +impl From for Log { + fn from(e: LocalizedLogEntry) -> Log { + Log { + address: e.entry.address, + topics: e.entry.topics, + data: Bytes::new(e.entry.data), + block_hash: e.block_hash, + block_number: From::from(e.block_number), + transaction_hash: e.transaction_hash, + transaction_index: From::from(e.transaction_index), + log_index: From::from(e.log_index) + } + } +} diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index c4c6e8295..34c1f1cff 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -19,6 +19,7 @@ mod block_number; mod bytes; mod filter; mod index; +mod log; mod optionals; mod sync; mod transaction; @@ -28,6 +29,7 @@ pub use self::block_number::BlockNumber; pub use self::bytes::Bytes; pub use self::filter::Filter; pub use self::index::Index; +pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; From 68d546ce02cb00ad3dea1b789b4888a5d978d186 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 17 Feb 2016 14:45:25 +0100 Subject: [PATCH 073/753] tests for log serialization --- rpc/src/v1/impls/eth.rs | 1 - rpc/src/v1/types/log.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 42e58493a..689afd019 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -210,7 +210,6 @@ impl Eth for EthClient { } } - /// Eth filter rpc implementation. pub struct EthFilterClient { client: Arc diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 4b8661075..83880a222 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -50,3 +50,34 @@ impl From for Log { } } } + +#[cfg(test)] +mod tests { + use serde_json; + use std::str::FromStr; + use util::hash::*; + use util::uint::*; + use v1::types::{Bytes, Log}; + + #[test] + fn log_serialization() { + let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","logIndex":"0x01"}"#; + + let log = Log { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: Bytes::new(vec![]), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + transaction_hash: H256::new(), + transaction_index: U256::zero(), + log_index: U256::one() + }; + + let serialized = serde_json::to_string(&log).unwrap(); + assert_eq!(serialized, s); + } +} From 49027c529a37aee13c6488fb898f9650dc45e854 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 17 Feb 2016 14:46:23 +0100 Subject: [PATCH 074/753] increase db version --- ethcore/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index ba3c97422..8e49d28bf 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -187,7 +187,7 @@ pub struct Client { } const HISTORY: u64 = 1000; -const CLIENT_DB_VER_STR: &'static str = "2.1"; +const CLIENT_DB_VER_STR: &'static str = "3"; impl Client { /// Create a new client with given spec and DB path. From 046984f7e84b22253c370010b1effa16572b261e Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 17 Feb 2016 14:57:54 +0100 Subject: [PATCH 075/753] fixed log transaction hashes --- ethcore/src/client.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 8e49d28bf..ba34d9a5e 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -497,7 +497,9 @@ impl BlockChainClient for Client { .filter_map(|m| m) .map(|(number, hash)| self.chain.read().unwrap().block_receipts(&hash).map(|r| (number, hash, r.receipts))) .filter_map(|m| m) - .map(|(number, hash, receipts)| { + .map(|(number, hash, receipts)| self.chain.read().unwrap().block(&hash).map(|ref b| (number, hash, receipts, BlockView::new(b).transaction_hashes()))) + .filter_map(|m| m) + .map(|(number, hash, receipts, hashes)| { let mut log_index = 0; receipts.into_iter() .enumerate() @@ -510,7 +512,7 @@ impl BlockChainClient for Client { entry: log, block_hash: hash.clone(), block_number: number as usize, - transaction_hash: H256::new(), + transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new), transaction_index: index, log_index: log_index + i }) From aad49cb19f7205ad0f5c97c9e418df50a839b126 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 23:25:25 +0300 Subject: [PATCH 076/753] more functional --- util/src/keys/directory.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 7cc101da1..f6d9c8e22 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -510,19 +510,16 @@ impl KeyDirectory { cache_usage.drain(..untracked_usages); } - let mut cache = self.cache.borrow_mut(); - if cache.len() <= MAX_CACHE_USAGE_TRACK { return; } + if self.cache.borrow().len() <= MAX_CACHE_USAGE_TRACK { return; } let uniqs: HashSet<&Uuid> = cache_usage.iter().collect(); - let mut removes = HashSet::new(); - - for key in cache.keys() { - if !uniqs.contains(key) { - removes.insert(key.clone()); - } + let removes: Vec = { + let cache = self.cache.borrow(); + cache.keys().cloned().filter(|key| !uniqs.contains(key)).collect() + }; + for key in removes { + self.cache.borrow_mut().remove(&key); } - - for removed_key in removes { cache.remove(&removed_key); } } /// Reports how many keys are currently cached. From 95c74dbd30e092c24f142c4e17ada412de7d4dec Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 23:34:55 +0300 Subject: [PATCH 077/753] more func --- util/src/keys/directory.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index f6d9c8e22..8ebf2c27d 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -513,13 +513,13 @@ impl KeyDirectory { if self.cache.borrow().len() <= MAX_CACHE_USAGE_TRACK { return; } let uniqs: HashSet<&Uuid> = cache_usage.iter().collect(); - let removes: Vec = { + let removes:Vec = { let cache = self.cache.borrow(); cache.keys().cloned().filter(|key| !uniqs.contains(key)).collect() }; - for key in removes { - self.cache.borrow_mut().remove(&key); - } + if removes.is_empty() { return } + let mut cache = self.cache.borrow_mut(); + for key in removes { cache.remove(&key); } } /// Reports how many keys are currently cached. From fffd93607d488575737710a810aa06b5d879d53f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 17 Feb 2016 23:38:16 +0300 Subject: [PATCH 078/753] just in case check --- util/src/keys/directory.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 8ebf2c27d..9c01d1974 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -517,7 +517,7 @@ impl KeyDirectory { let cache = self.cache.borrow(); cache.keys().cloned().filter(|key| !uniqs.contains(key)).collect() }; - if removes.is_empty() { return } + if removes.is_empty() { return; } let mut cache = self.cache.borrow_mut(); for key in removes { cache.remove(&key); } } @@ -1093,6 +1093,14 @@ mod directory_tests { // since all keys are different, should be exactly MAX_CACHE_USAGE_TRACK assert_eq!(MAX_CACHE_USAGE_TRACK, directory.cache_size()) } + + #[test] + fn collects_garbage_on_empty() { + let temp_path = RandomTempPath::create_dir(); + let mut directory = KeyDirectory::new(&temp_path.as_path()); + directory.collect_garbage(); + assert_eq!(0, directory.cache_size()) + } } #[cfg(test)] From 68d606b5f0ce3835c8962cacd52a134c64d4d2c3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 18 Feb 2016 03:46:24 +0100 Subject: [PATCH 079/753] rocksdb abstraction layer --- Cargo.lock | 22 +++++++++++--- ethcore/Cargo.toml | 1 - ethcore/src/blockchain.rs | 15 +++++----- ethcore/src/client.rs | 28 ++---------------- ethcore/src/extras.rs | 5 ++-- ethcore/src/lib.rs | 1 - ethcore/src/tests/helpers.rs | 7 ++--- util/Cargo.toml | 2 +- util/src/journaldb.rs | 56 ++++++++++++++++++++---------------- util/src/lib.rs | 2 ++ util/src/overlaydb.rs | 14 ++++----- 11 files changed, 72 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e9f57900..1ee6e116c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,7 +176,6 @@ dependencies = [ "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -217,7 +216,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rocksdb 0.3.0 (git+https://github.com/arkpar/rust-rocksdb.git)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -397,6 +396,15 @@ name = "libc" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "librocksdb-sys" +version = "0.1.0" +source = "git+https://github.com/arkpar/rust-rocksdb.git#e7f79d31e467c405a12db629daf5a86f81ed3e60" +dependencies = [ + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "linked-hash-map" version = "0.0.8" @@ -525,6 +533,11 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pkg-config" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quasi" version = "0.6.0" @@ -573,9 +586,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/arkpar/rust-rocksdb.git#e7f79d31e467c405a12db629daf5a86f81ed3e60" dependencies = [ - "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "librocksdb-sys 0.1.0 (git+https://github.com/arkpar/rust-rocksdb.git)", ] [[package]] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 3d4d27520..97d93f3b8 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -10,7 +10,6 @@ authors = ["Ethcore "] log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" -rocksdb = "0.3" heapsize = "0.2.0" rust-crypto = "0.2.34" time = "0.1" diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 9240ff800..8518ef121 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -17,7 +17,6 @@ //! Blockchain database. use util::*; -use rocksdb::{DB, WriteBatch, Writable}; use header::*; use extras::*; use transaction::*; @@ -162,8 +161,8 @@ pub struct BlockChain { block_logs: RwLock>, blocks_blooms: RwLock>, - extras_db: DB, - blocks_db: DB, + extras_db: Database, + blocks_db: Database, cache_man: RwLock, } @@ -250,12 +249,12 @@ impl BlockChain { // open extras db let mut extras_path = path.to_path_buf(); extras_path.push("extras"); - let extras_db = DB::open_default(extras_path.to_str().unwrap()).unwrap(); + let extras_db = Database::open_default(extras_path.to_str().unwrap()).unwrap(); // open blocks db let mut blocks_path = path.to_path_buf(); blocks_path.push("blocks"); - let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap(); + let blocks_db = Database::open_default(blocks_path.to_str().unwrap()).unwrap(); let mut cache_man = CacheManager{cache_usage: VecDeque::new(), in_use: HashSet::new()}; (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new())); @@ -294,7 +293,7 @@ impl BlockChain { bc.blocks_db.put(&hash, genesis).unwrap(); - let batch = WriteBatch::new(); + let batch = DBTransaction::new(); batch.put_extras(&hash, &details); batch.put_extras(&header.number(), &hash); batch.put(b"best", &hash).unwrap(); @@ -457,7 +456,7 @@ impl BlockChain { /// Transforms block into WriteBatch that may be written into database /// Additionally, if it's new best block it returns new best block object. - fn block_to_extras_insert_batch(&self, bytes: &[u8]) -> (WriteBatch, Option, BlockDetails) { + fn block_to_extras_insert_batch(&self, bytes: &[u8]) -> (DBTransaction, Option, BlockDetails) { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -478,7 +477,7 @@ impl BlockChain { }; // prepare the batch - let batch = WriteBatch::new(); + let batch = DBTransaction::new(); // insert new block details batch.put_extras(&hash, &details); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 09f7417e8..762adc113 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -18,7 +18,6 @@ use util::*; use util::panics::*; -use rocksdb::{Options, DB, DBCompactionStyle}; use blockchain::{BlockChain, BlockProvider, CacheSize}; use views::BlockView; use error::*; @@ -179,7 +178,7 @@ pub struct Client { } const HISTORY: u64 = 1000; -const CLIENT_DB_VER_STR: &'static str = "2.1"; +const CLIENT_DB_VER_STR: &'static str = "3.0"; impl Client { /// Create a new client with given spec and DB path. @@ -191,34 +190,11 @@ impl Client { let path = dir.as_path(); let gb = spec.genesis_block(); let chain = Arc::new(RwLock::new(BlockChain::new(&gb, path))); - let mut opts = Options::new(); - opts.set_max_open_files(256); - opts.create_if_missing(true); - opts.set_use_fsync(false); - opts.set_compaction_style(DBCompactionStyle::DBUniversalCompaction); - /* - opts.set_bytes_per_sync(8388608); - opts.set_disable_data_sync(false); - opts.set_block_cache_size_mb(1024); - opts.set_table_cache_num_shard_bits(6); - opts.set_max_write_buffer_number(32); - opts.set_write_buffer_size(536870912); - opts.set_target_file_size_base(1073741824); - opts.set_min_write_buffer_number_to_merge(4); - opts.set_level_zero_stop_writes_trigger(2000); - opts.set_level_zero_slowdown_writes_trigger(0); - opts.set_compaction_style(DBUniversalCompaction); - opts.set_max_background_compactions(4); - opts.set_max_background_flushes(4); - opts.set_filter_deletes(false); - opts.set_disable_auto_compactions(false);*/ - let mut state_path = path.to_path_buf(); state_path.push("state"); - let db = Arc::new(DB::open(&opts, state_path.to_str().unwrap()).unwrap()); let engine = Arc::new(try!(spec.to_engine())); - let mut state_db = JournalDB::new_with_arc(db.clone()); + let mut state_db = JournalDB::new(state_path.to_str().unwrap()); if state_db.is_empty() && engine.spec().ensure_db_good(&mut state_db) { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); } diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index b65d4ed7a..3188378fc 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -18,7 +18,6 @@ use util::*; use header::BlockNumber; -use rocksdb::{DB, Writable}; /// Represents index of extra data in database #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] @@ -56,7 +55,7 @@ pub trait ExtrasReadable { K: ExtrasSliceConvertable; } -impl ExtrasWritable for W where W: Writable { +impl ExtrasWritable for DBTransaction { fn put_extras(&self, hash: &K, value: &T) where T: ExtrasIndexable + Encodable, K: ExtrasSliceConvertable { @@ -65,7 +64,7 @@ impl ExtrasWritable for W where W: Writable { } } -impl ExtrasReadable for DB { +impl ExtrasReadable for Database { fn get_extras(&self, hash: &K) -> Option where T: ExtrasIndexable + Decodable, K: ExtrasSliceConvertable { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 4cca74319..1b4d4e6ca 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -86,7 +86,6 @@ #[macro_use] extern crate ethcore_util as util; #[macro_use] extern crate lazy_static; extern crate rustc_serialize; -extern crate rocksdb; extern crate heapsize; extern crate crypto; extern crate time; diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 93e3e0a0d..550fc8937 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -22,7 +22,6 @@ use spec::*; use std::fs::{remove_dir_all}; use blockchain::{BlockChain}; use state::*; -use rocksdb::*; use evm::{Schedule, Factory}; use engine::*; use ethereum; @@ -258,8 +257,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { pub fn get_temp_journal_db() -> GuardedTempResult { let temp = RandomTempPath::new(); - let db = DB::open_default(temp.as_str()).unwrap(); - let journal_db = JournalDB::new(db); + let journal_db = JournalDB::new(temp.as_str()); GuardedTempResult { _temp: temp, result: Some(journal_db) @@ -276,8 +274,7 @@ pub fn get_temp_state() -> GuardedTempResult { } pub fn get_temp_journal_db_in(path: &Path) -> JournalDB { - let db = DB::open_default(path.to_str().unwrap()).unwrap(); - JournalDB::new(db) + JournalDB::new(path.to_str().unwrap()) } pub fn get_temp_state_in(path: &Path) -> State { diff --git a/util/Cargo.toml b/util/Cargo.toml index 9ead8ccf6..67ac2a0bb 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -15,7 +15,7 @@ mio = "0.5.0" rand = "0.3.12" time = "0.1.34" tiny-keccak = "1.0" -rocksdb = "0.3" +rocksdb = { git = "https://github.com/arkpar/rust-rocksdb.git" } lazy_static = "0.1" eth-secp256k1 = { git = "https://github.com/arkpar/rust-secp256k1.git" } rust-crypto = "0.2.34" diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 7b810639b..8d31f50eb 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -20,7 +20,7 @@ use common::*; use rlp::*; use hashdb::*; use memorydb::*; -use rocksdb::{DB, Writable, WriteBatch, IteratorMode}; +use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; @@ -33,7 +33,7 @@ use std::env; /// the removals actually take effect. pub struct JournalDB { overlay: MemoryDB, - backing: Arc, + backing: Arc, counters: Arc>>, } @@ -47,21 +47,25 @@ impl Clone for JournalDB { } } -const LATEST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; -const VERSION_KEY : [u8; 4] = [ b'j', b'v', b'e', b'r' ]; +// all keys must be at least 12 bytes +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; -const DB_VERSION: u32 = 2; +const DB_VERSION: u32 = 3; + +const PADDING : [u8; 10] = [ 0u8; 10 ]; impl JournalDB { - /// Create a new instance given a `backing` database. - pub fn new(backing: DB) -> JournalDB { - let db = Arc::new(backing); - JournalDB::new_with_arc(db) - } - /// Create a new instance given a shared `backing` database. - pub fn new_with_arc(backing: Arc) -> JournalDB { - if backing.iterator(IteratorMode::Start).next().is_some() { + /// Create a new instance from file + pub fn new(path: &str) -> JournalDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + if !backing.is_empty() { match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { Ok(Some(DB_VERSION)) => {}, v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) @@ -72,7 +76,7 @@ impl JournalDB { let counters = JournalDB::read_counters(&backing); JournalDB { overlay: MemoryDB::new(), - backing: backing, + backing: Arc::new(backing), counters: Arc::new(RwLock::new(counters)), } } @@ -82,7 +86,7 @@ impl JournalDB { pub fn new_temp() -> JournalDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); - Self::new(DB::open_default(dir.to_str().unwrap()).unwrap()) + Self::new(dir.to_str().unwrap()) } /// Check if this database has any commits @@ -117,16 +121,17 @@ impl JournalDB { // and the key is safe to delete. // record new commit's details. - let batch = WriteBatch::new(); + let batch = DBTransaction::new(); let mut counters = self.counters.write().unwrap(); { let mut index = 0usize; let mut last; while try!(self.backing.get({ - let mut r = RlpStream::new_list(2); + let mut r = RlpStream::new_list(3); r.append(&now); r.append(&index); + r.append(&&PADDING[..]); last = r.drain(); &last })).is_some() { @@ -154,9 +159,10 @@ impl JournalDB { let mut to_remove: Vec = Vec::new(); let mut canon_inserts: Vec = Vec::new(); while let Some(rlp_data) = try!(self.backing.get({ - let mut r = RlpStream::new_list(2); + let mut r = RlpStream::new_list(3); r.append(&end_era); r.append(&index); + r.append(&&PADDING[..]); last = r.drain(); &last })) { @@ -226,16 +232,17 @@ impl JournalDB { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } - fn read_counters(db: &DB) -> HashMap { + fn read_counters(db: &Database) -> HashMap { let mut res = HashMap::new(); if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { let mut era = decode::(&val); loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ - let mut r = RlpStream::new_list(2); + let mut r = RlpStream::new_list(3); r.append(&era); r.append(&index); + r.append(&&PADDING[..]); &r.drain() }).expect("Low-level database error.") { let rlp = Rlp::new(&rlp_data); @@ -259,7 +266,7 @@ impl JournalDB { impl HashDB for JournalDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); - for (key, _) in self.backing.iterator(IteratorMode::Start) { + for (key, _) in self.backing.iter() { let h = H256::from_slice(key.deref()); ret.insert(h, 1); } @@ -429,12 +436,11 @@ mod tests { #[test] fn reopen() { - use rocksdb::DB; let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); let foo = { - let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -442,13 +448,13 @@ mod tests { }; { - let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); } { - let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); assert!(jdb.exists(&foo)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); assert!(!jdb.exists(&foo)); diff --git a/util/src/lib.rs b/util/src/lib.rs index d4f972800..41d0ebe00 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -128,6 +128,7 @@ pub mod hashdb; pub mod memorydb; pub mod overlaydb; pub mod journaldb; +pub mod kvdb; mod math; pub mod chainfilter; pub mod crypto; @@ -162,6 +163,7 @@ pub use semantic_version::*; pub use network::*; pub use io::*; pub use log::*; +pub use kvdb::*; #[cfg(test)] mod tests; diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index f8e9c3eee..f4ed2d5d6 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -26,7 +26,7 @@ use std::ops::*; use std::sync::*; use std::env; use std::collections::HashMap; -use rocksdb::{DB, Writable, IteratorMode}; +use kvdb::{Database}; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay. /// @@ -38,15 +38,15 @@ use rocksdb::{DB, Writable, IteratorMode}; /// queries have an immediate effect in terms of these functions. pub struct OverlayDB { overlay: MemoryDB, - backing: Arc, + backing: Arc, } impl OverlayDB { /// Create a new instance of OverlayDB given a `backing` database. - pub fn new(backing: DB) -> OverlayDB { Self::new_with_arc(Arc::new(backing)) } + pub fn new(backing: Database) -> OverlayDB { Self::new_with_arc(Arc::new(backing)) } /// Create a new instance of OverlayDB given a `backing` database. - pub fn new_with_arc(backing: Arc) -> OverlayDB { + pub fn new_with_arc(backing: Arc) -> OverlayDB { OverlayDB{ overlay: MemoryDB::new(), backing: backing } } @@ -54,7 +54,7 @@ impl OverlayDB { pub fn new_temp() -> OverlayDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); - Self::new(DB::open_default(dir.to_str().unwrap()).unwrap()) + Self::new(Database::open_default(dir.to_str().unwrap()).unwrap()) } /// Commit all memory operations to the backing database. @@ -164,7 +164,7 @@ impl OverlayDB { impl HashDB for OverlayDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); - for (key, _) in self.backing.iterator(IteratorMode::Start) { + for (key, _) in self.backing.iter() { let h = H256::from_slice(key.deref()); let r = self.payload(&h).unwrap().1; ret.insert(h, r as i32); @@ -318,7 +318,7 @@ fn overlaydb_complex() { fn playpen() { use std::fs; { - let db: DB = DB::open_default("/tmp/test").unwrap(); + let db: Database = Database::open_default("/tmp/test").unwrap(); db.put(b"test", b"test2").unwrap(); match db.get(b"test") { Ok(Some(value)) => println!("Got value {:?}", value.deref()), From e99f604133ceb19383aefb88d4a4ff72578e5eb4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 18 Feb 2016 03:46:34 +0100 Subject: [PATCH 080/753] rocksdb abstraction layer --- util/src/kvdb.rs | 150 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 util/src/kvdb.rs diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs new file mode 100644 index 000000000..a5691bcba --- /dev/null +++ b/util/src/kvdb.rs @@ -0,0 +1,150 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Key-Value store abstraction with rocksb backend. + +use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBVector, DBIterator, + IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction}; + +/// Write transaction. Batches a sequence of put/delete operations for efficiency. +pub struct DBTransaction { + batch: WriteBatch, +} + +impl DBTransaction { + /// Create new transaction. + pub fn new() -> DBTransaction { + DBTransaction { batch: WriteBatch::new() } + } + + /// Insert a ket-value pair in the transaction. Any existing value value will be overwritten upon write. + pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { + self.batch.put(key, value) + } + + /// Delete value by key. + pub fn delete(&self, key: &[u8]) -> Result<(), String> { + self.batch.delete(key) + } +} + +/// Database configuration +pub struct DatabaseConfig { + /// Optional prefix size in bytes. Allows lookup by partial key. + pub prefix_size: Option +} + +/// Database iterator +pub struct DatabaseIterator<'a> { + iter: DBIterator<'a>, +} + +impl<'a> Iterator for DatabaseIterator<'a> { + type Item = (Box<[u8]>, Box<[u8]>); + + #[allow(type_complexity)] + fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> { + self.iter.next() + } +} + +/// Key-Value database. +pub struct Database { + db: DB, +} + +impl Database { + /// Open database with default settings. + pub fn open_default(path: &str) -> Result { + Database::open(DatabaseConfig { prefix_size: None }, path) + } + + /// Open database file. Creates if it does not exist. + pub fn open(config: DatabaseConfig, path: &str) -> Result { + let mut opts = Options::new(); + opts.set_max_open_files(256); + opts.create_if_missing(true); + opts.set_use_fsync(false); + opts.set_compaction_style(DBCompactionStyle::DBUniversalCompaction); + /* + opts.set_bytes_per_sync(8388608); + opts.set_disable_data_sync(false); + opts.set_block_cache_size_mb(1024); + opts.set_table_cache_num_shard_bits(6); + opts.set_max_write_buffer_number(32); + opts.set_write_buffer_size(536870912); + opts.set_target_file_size_base(1073741824); + opts.set_min_write_buffer_number_to_merge(4); + opts.set_level_zero_stop_writes_trigger(2000); + opts.set_level_zero_slowdown_writes_trigger(0); + opts.set_compaction_style(DBUniversalCompaction); + opts.set_max_background_compactions(4); + opts.set_max_background_flushes(4); + opts.set_filter_deletes(false); + opts.set_disable_auto_compactions(false);*/ + + if let Some(size) = config.prefix_size { + let mut block_opts = BlockBasedOptions::new(); + block_opts.set_index_type(IndexType::HashSearch); + opts.set_block_based_table_factory(&block_opts); + opts.set_prefix_extractor_fixed_size(size); + } + let db = try!(DB::open(&opts, path)); + Ok(Database { db: db }) + } + + /// Insert a ket-value pair in the transaction. Any existing value value will be overwritten. + pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { + self.db.put(key, value) + } + + /// Delete value by key. + pub fn delete(&self, key: &[u8]) -> Result<(), String> { + self.db.delete(key) + } + + /// Commit transaction to database. + pub fn write(&self, tr: DBTransaction) -> Result<(), String> { + self.db.write(tr.batch) + } + + /// Get value by key. + pub fn get(&self, key: &[u8]) -> Result, String> { + self.db.get(key) + } + + /// Get value by partial key. Prefix size should match configured prefix size. + pub fn get_by_prefix(&self, prefix: &[u8]) -> Option> { + let mut iter = self.db.iterator(IteratorMode::From(prefix, Direction::forward)); + match iter.next() { + // TODO: use prefix_same_as_start read option (not availabele in C API currently) + Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Some(v) } else { None }, + _ => None + } + } + + /// Check if there is anything in the database. + pub fn is_empty(&self) -> bool { + self.db.iterator(IteratorMode::Start).next().is_none() + } + + /// Check if there is anything in the database. + pub fn iter(&self) -> DatabaseIterator { + DatabaseIterator { iter: self.db.iterator(IteratorMode::Start) } + } +} + + From 97f549cf5f3287ad0a4f37982d80641ed03cd6c6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 12:42:01 +0100 Subject: [PATCH 081/753] Add daemonization. --- Cargo.lock | 9 ++++ Cargo.toml | 1 + parity/main.rs | 122 ++++++++++++++++++++++++++++++------------------- 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e9f57900..87a599f3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,7 @@ version = "0.9.99" dependencies = [ "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.0.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", + "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "docopt_macros 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -108,6 +109,14 @@ dependencies = [ "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "daemonize" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "docopt" version = "0.6.78" diff --git a/Cargo.toml b/Cargo.toml index c58cacf0d..828ed32e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" +daemonize = "0.2" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index 460922b64..d0bc05a08 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -25,11 +25,13 @@ extern crate rustc_serialize; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; +#[macro_use] extern crate log as rlog; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate target_info; +extern crate daemonize; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -48,6 +50,7 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use target_info::Target; +use daemonize::{Daemonize}; docopt!(Args derive Debug, " Parity. Ethereum Client. @@ -55,12 +58,14 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file - or frontier, mainnet, morden, or testnet [default: frontier]. + or frontier, mainnet, morden, or testnet [default: frontier]. -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] + --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --no-bootstrap Don't bother trying to connect to any nodes initially. --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. @@ -136,6 +141,10 @@ impl Configuration { self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } + fn keys_path(&self) -> String { + self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + } + fn spec(&self) -> Spec { match self.args.flag_chain.as_ref() { "frontier" | "mainnet" => ethereum::new_frontier(), @@ -171,6 +180,71 @@ impl Configuration { (listen_address, public_address) } + + fn execute(&self) { + if self.args.flag_version { + print_version(); + return; + } + if self.args.cmd_daemon { + let daemonize = Daemonize::new() + .pid_file("/tmp/parity.pid") // Every method except `new` and `start` + .chown_pid_file(true) // is optional, see `Daemonize` documentation + .working_directory("/tmp") // for default behaviour. + .user("nobody") + .group("daemon") // Group name + .group(2) // Or group id + .privileged_action(|| "Executed before drop privileges"); + + match daemonize.start() { + Ok(_) => info!("Success, daemonized"), + Err(e) => { error!("{}", e); return; }, + } + } + self.execute_client(); + } + + fn execute_client(&self) { + // Setup logging + setup_log(&self.args.flag_logging); + // Raise fdlimit + unsafe { ::fdlimit::raise_fd_limit(); } + + let spec = self.spec(); + + // Configure network + let mut net_settings = NetworkConfiguration::new(); + net_settings.nat_enabled = self.args.flag_upnp; + net_settings.boot_nodes = self.init_nodes(&spec); + let (listen, public) = self.net_addresses(); + net_settings.listen_address = listen; + net_settings.public_address = public; + net_settings.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); + + // Build client + let mut service = ClientService::start(spec, net_settings, &Path::new(&self.path())).unwrap(); + let client = service.client().clone(); + client.configure_cache(self.args.flag_cache_pref_size, self.args.flag_cache_max_size); + + // Sync + let sync = EthSync::register(service.network(), client); + + // Setup rpc + if self.args.flag_jsonrpc { + setup_rpc_server(service.client(), sync.clone(), &self.args.flag_jsonrpc_url); + } + + // Register IO handler + let io_handler = Arc::new(ClientIoHandler { + client: service.client(), + info: Default::default(), + sync: sync + }); + service.io().register_handler(io_handler).expect("Error registering IO handler"); + + // Handle exit + wait_for_exit(&service); + } } fn wait_for_exit(client_service: &ClientService) { @@ -186,51 +260,7 @@ fn wait_for_exit(client_service: &ClientService) { } fn main() { - let conf = Configuration::parse(); - if conf.args.flag_version { - print_version(); - return; - } - - let spec = conf.spec(); - - // Setup logging - setup_log(&conf.args.flag_logging); - // Raise fdlimit - unsafe { ::fdlimit::raise_fd_limit(); } - - // Configure network - let mut net_settings = NetworkConfiguration::new(); - net_settings.nat_enabled = conf.args.flag_upnp; - net_settings.boot_nodes = conf.init_nodes(&spec); - let (listen, public) = conf.net_addresses(); - net_settings.listen_address = listen; - net_settings.public_address = public; - net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); - - // Build client - let mut service = ClientService::start(spec, net_settings, &Path::new(&conf.path())).unwrap(); - let client = service.client().clone(); - client.configure_cache(conf.args.flag_cache_pref_size, conf.args.flag_cache_max_size); - - // Sync - let sync = EthSync::register(service.network(), client); - - // Setup rpc - if conf.args.flag_jsonrpc { - setup_rpc_server(service.client(), sync.clone(), &conf.args.flag_jsonrpc_url); - } - - // Register IO handler - let io_handler = Arc::new(ClientIoHandler { - client: service.client(), - info: Default::default(), - sync: sync - }); - service.io().register_handler(io_handler).expect("Error registering IO handler"); - - // Handle exit - wait_for_exit(&service); + Configuration::parse().execute(); } struct Informant { From ca353dd18e37fc7d2a25fd22927311ec1ebf8285 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:07:57 +0100 Subject: [PATCH 082/753] Remove daemonize feature. --- parity/main.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index d0bc05a08..8af61ca93 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -31,7 +31,6 @@ extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate target_info; -extern crate daemonize; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -50,7 +49,6 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use target_info::Target; -use daemonize::{Daemonize}; docopt!(Args derive Debug, " Parity. Ethereum Client. @@ -58,7 +56,6 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -186,21 +183,6 @@ impl Configuration { print_version(); return; } - if self.args.cmd_daemon { - let daemonize = Daemonize::new() - .pid_file("/tmp/parity.pid") // Every method except `new` and `start` - .chown_pid_file(true) // is optional, see `Daemonize` documentation - .working_directory("/tmp") // for default behaviour. - .user("nobody") - .group("daemon") // Group name - .group(2) // Or group id - .privileged_action(|| "Executed before drop privileges"); - - match daemonize.start() { - Ok(_) => info!("Success, daemonized"), - Err(e) => { error!("{}", e); return; }, - } - } self.execute_client(); } From 870731cb9fe76a0689c62cdcbda992801608c70c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:08:25 +0100 Subject: [PATCH 083/753] No need to bring in daemonize module. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 828ed32e7..c58cacf0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" -daemonize = "0.2" [features] default = ["rpc"] From 7f2acedf9fce9cc0cb0383bf6027d46ec7e0448e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:10:04 +0100 Subject: [PATCH 084/753] Reintroduce daemonize. --- Cargo.toml | 1 + parity/main.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index c58cacf0d..828ed32e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" +daemonize = "0.2" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index 8af61ca93..d0bc05a08 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -31,6 +31,7 @@ extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate target_info; +extern crate daemonize; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -49,6 +50,7 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use target_info::Target; +use daemonize::{Daemonize}; docopt!(Args derive Debug, " Parity. Ethereum Client. @@ -56,6 +58,7 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -183,6 +186,21 @@ impl Configuration { print_version(); return; } + if self.args.cmd_daemon { + let daemonize = Daemonize::new() + .pid_file("/tmp/parity.pid") // Every method except `new` and `start` + .chown_pid_file(true) // is optional, see `Daemonize` documentation + .working_directory("/tmp") // for default behaviour. + .user("nobody") + .group("daemon") // Group name + .group(2) // Or group id + .privileged_action(|| "Executed before drop privileges"); + + match daemonize.start() { + Ok(_) => info!("Success, daemonized"), + Err(e) => { error!("{}", e); return; }, + } + } self.execute_client(); } From c6bcd464c2689cac0e3860aa41f9e5bba3480da8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:54:18 +0100 Subject: [PATCH 085/753] Avoid changing user for daemonize. Just stick to the basics. --- parity/main.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index d0bc05a08..7e66fcbab 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -58,7 +58,7 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -187,19 +187,11 @@ impl Configuration { return; } if self.args.cmd_daemon { - let daemonize = Daemonize::new() - .pid_file("/tmp/parity.pid") // Every method except `new` and `start` - .chown_pid_file(true) // is optional, see `Daemonize` documentation - .working_directory("/tmp") // for default behaviour. - .user("nobody") - .group("daemon") // Group name - .group(2) // Or group id - .privileged_action(|| "Executed before drop privileges"); - - match daemonize.start() { - Ok(_) => info!("Success, daemonized"), - Err(e) => { error!("{}", e); return; }, - } + let daemonize = Daemonize::new().pid_file(self.args.arg_pid_file.clone()).chown_pid_file(true); + match daemonize.start() { + Ok(_) => info!("Daemonized"), + Err(e) => { error!("{}", e); return; }, + } } self.execute_client(); } From 379876341e208cf58aea388dc0fda427d722bb91 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:56:15 +0100 Subject: [PATCH 086/753] Correct alignment. --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 7e66fcbab..e557316c1 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -63,7 +63,7 @@ Usage: Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file - or frontier, mainnet, morden, or testnet [default: frontier]. + or frontier, mainnet, morden, or testnet [default: frontier]. -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] From 1447fb9d30e6f2ebeefd704b72d9f7980f880202 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 14:16:55 +0100 Subject: [PATCH 087/753] Switch to using non-macro ready for beta. --- parity/main.rs | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index e557316c1..50c9a78cb 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -18,7 +18,6 @@ #![warn(missing_docs)] #![feature(plugin)] -#![plugin(docopt_macros)] #![plugin(clippy)] extern crate docopt; extern crate rustc_serialize; @@ -49,10 +48,11 @@ use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; +use docopt::Docopt; use target_info::Target; -use daemonize::{Daemonize}; +use daemonize::Daemonize; -docopt!(Args derive Debug, " +const USAGE: &'static str = " Parity. Ethereum Client. By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf. Copyright 2015, 2016 Ethcore (UK) Limited @@ -83,9 +83,31 @@ Options: -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. -", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option, flag_node_key: Option); +"; -fn setup_log(init: &str) { +#[derive(Debug, RustcDecodable)] +struct Args { + cmd_daemon: bool, + arg_pid_file: String, + arg_enode: Vec, + flag_chain: String, + flag_db_path: String, + flag_keys_path: String, + flag_no_bootstrap: bool, + flag_listen_address: String, + flag_public_address: String, + flag_address: Option, + flag_upnp: bool, + flag_node_key: Option, + flag_cache_pref_size: usize, + flag_cache_max_size: usize, + flag_jsonrpc: bool, + flag_jsonrpc_url: String, + flag_logging: Option, + flag_version: bool, +} + +fn setup_log(init: &Option) { let mut builder = LogBuilder::new(); builder.filter(None, LogLevelFilter::Info); @@ -93,7 +115,9 @@ fn setup_log(init: &str) { builder.parse(&env::var("RUST_LOG").unwrap()); } - builder.parse(init); + if let Some(ref s) = *init { + builder.parse(s); + } builder.init().unwrap(); } @@ -133,7 +157,7 @@ struct Configuration { impl Configuration { fn parse() -> Self { Configuration { - args: Args::docopt().decode().unwrap_or_else(|e| e.exit()) + args: Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()), } } From 7d75626e75b81bc3347039af9169cbc9d10be405 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 14:28:24 +0100 Subject: [PATCH 088/753] Fix options. --- parity/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 50c9a78cb..077d92e54 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -58,7 +58,7 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -182,7 +182,7 @@ impl Configuration { if self.args.flag_no_bootstrap { Vec::new() } else { match self.args.arg_enode.len() { 0 => spec.nodes().clone(), - _ => self.args.arg_enode.clone(), + _ => self.args.arg_enode.clone(), // TODO check format first. } } } From ebe8e19cc0d8152daf13454d0d6231491c3112e3 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 18 Feb 2016 14:36:59 +0100 Subject: [PATCH 089/753] fixed compiling with rustc 1.8.0-nightly (57c357d89 2016-02-16) --- Cargo.lock | 87 +++++++++++++++++++++++++++++++--------------- Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- rpc/Cargo.toml | 18 +++++++--- rpc/build.rs | 29 ++++++++++++++++ rpc/src/lib.rs | 44 ++++------------------- rpc/src/lib.rs.in | 30 ++++++++++++++++ sync/Cargo.toml | 2 +- util/Cargo.toml | 2 +- 9 files changed, 142 insertions(+), 74 deletions(-) create mode 100644 rpc/build.rs create mode 100644 rpc/src/lib.rs.in diff --git a/Cargo.lock b/Cargo.lock index 1e9f57900..32a6326f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "parity" version = "0.9.99" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.0.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "docopt_macros 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)", @@ -38,6 +38,9 @@ dependencies = [ name = "aster" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "bitflags" @@ -61,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.41" +version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "regex-syntax 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -167,7 +170,7 @@ dependencies = [ name = "ethcore" version = "0.9.99" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", @@ -186,16 +189,17 @@ dependencies = [ name = "ethcore-rpc" version = "0.9.99" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", - "jsonrpc-core 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -204,7 +208,7 @@ name = "ethcore-util" version = "0.9.99" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -232,7 +236,7 @@ dependencies = [ name = "ethsync" version = "0.9.99" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", @@ -346,12 +350,13 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -360,7 +365,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -529,6 +534,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "quasi" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "quasi_codegen" @@ -536,14 +544,8 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aster 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quasi_macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quasi_codegen 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -631,7 +633,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aster 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "quasi 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_macros 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -643,14 +647,6 @@ dependencies = [ "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "serde_macros" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde_codegen 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "sha3" version = "0.1.0" @@ -682,11 +678,41 @@ name = "strsim" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syntex" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_syntax" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "target_info" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "term" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.34" @@ -733,6 +759,11 @@ name = "unicode-normalization" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "url" version = "0.2.38" diff --git a/Cargo.toml b/Cargo.toml index c58cacf0d..0a55038dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ rustc-serialize = "0.3" docopt = "0.6" docopt_macros = "0.6" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } -clippy = "0.0.41" +clippy = "0.0.42" ethcore-util = { path = "util" } ethcore = { path = "ethcore" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 3d4d27520..5298a253f 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -18,7 +18,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = "0.0.41" +clippy = "0.0.42" crossbeam = "0.1.5" lazy_static = "0.1" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b1af0a2fa..4e79fa8f5 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -4,18 +4,28 @@ name = "ethcore-rpc" version = "0.9.99" license = "GPL-3.0" authors = ["Ethcore . //! Ethcore rpc. -#![warn(missing_docs)] -#![feature(custom_derive, custom_attribute, plugin)] -#![plugin(serde_macros)] -#![plugin(clippy)] +#![cfg_attr(nightly, feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(nightly, plugin(serde_macros, clippy))] extern crate rustc_serialize; extern crate target_info; @@ -30,38 +28,8 @@ extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; -use self::jsonrpc_core::{IoHandler, IoDelegate}; +#[cfg(feature = "serde_macros")] +include!("lib.rs.in"); -pub mod v1; - -/// Http server. -pub struct HttpServer { - handler: IoHandler, - threads: usize -} - -impl HttpServer { - /// Construct new http server object with given number of threads. - pub fn new(threads: usize) -> HttpServer { - HttpServer { - handler: IoHandler::new(), - threads: threads - } - } - - /// Add io delegate. - pub fn add_delegate(&mut self, delegate: IoDelegate) where D: Send + Sync + 'static { - self.handler.add_delegate(delegate); - } - - /// Start server asynchronously in new thread - pub fn start_async(self, addr: &str) { - let server = jsonrpc_http_server::Server::new(self.handler, self.threads); - server.start_async(addr) - } -} - -/// Lib needs at least 1 test to generate coverage reports correctly. -#[test] -fn if_works() { -} +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/lib.rs")); diff --git a/rpc/src/lib.rs.in b/rpc/src/lib.rs.in new file mode 100644 index 000000000..f09a25be8 --- /dev/null +++ b/rpc/src/lib.rs.in @@ -0,0 +1,30 @@ +use self::jsonrpc_core::{IoHandler, IoDelegate}; + +pub mod v1; + +/// Http server. +pub struct HttpServer { + handler: IoHandler, + threads: usize +} + +impl HttpServer { + /// Construct new http server object with given number of threads. + pub fn new(threads: usize) -> HttpServer { + HttpServer { + handler: IoHandler::new(), + threads: threads + } + } + + /// Add io delegate. + pub fn add_delegate(&mut self, delegate: IoDelegate) where D: Send + Sync + 'static { + self.handler.add_delegate(delegate); + } + + /// Start server asynchronously in new thread + pub fn start_async(self, addr: &str) { + let server = jsonrpc_http_server::Server::new(self.handler, self.threads); + server.start_async(addr) + } +} diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 92b46fc57..db1a7ba82 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore Date: Thu, 18 Feb 2016 15:17:26 +0100 Subject: [PATCH 090/753] updated heapsizeof --- Cargo.lock | 9 +++------ ethcore/Cargo.toml | 2 +- util/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32a6326f7..f895850a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,7 +175,7 @@ dependencies = [ "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", "ethcore-util 0.9.99", - "heapsize 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -213,7 +213,7 @@ dependencies = [ "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", - "heapsize 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", @@ -264,11 +264,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "heapsize" -version = "0.2.5" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "hpack" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 5298a253f..d8df6455a 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -11,7 +11,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" rocksdb = "0.3" -heapsize = "0.2.0" +heapsize = "0.3" rust-crypto = "0.2.34" time = "0.1" ethcore-util = { path = "../util" } diff --git a/util/Cargo.toml b/util/Cargo.toml index 8ca86d26b..a339d10e1 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "0.1" eth-secp256k1 = { git = "https://github.com/arkpar/rust-secp256k1.git" } rust-crypto = "0.2.34" elastic-array = "0.4" -heapsize = "0.2" +heapsize = "0.3" itertools = "0.4" crossbeam = "0.2" slab = { git = "https://github.com/arkpar/slab.git" } From 198119466b91951145736234cc69483f20885700 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 18 Feb 2016 19:21:24 +0300 Subject: [PATCH 091/753] forking heapsize --- Cargo.lock | 7 ++++++- util/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f895850a7..05f674a69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,7 +213,7 @@ dependencies = [ "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", - "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.2 (git+https://github.com/nikvolf/heapsize)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", @@ -262,6 +262,11 @@ name = "glob" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "heapsize" +version = "0.3.2" +source = "git+https://github.com/nikvolf/heapsize#7913872a4f928a49659df52e48dea69d8a2376bf" + [[package]] name = "heapsize" version = "0.3.2" diff --git a/util/Cargo.toml b/util/Cargo.toml index a339d10e1..ea618ed45 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "0.1" eth-secp256k1 = { git = "https://github.com/arkpar/rust-secp256k1.git" } rust-crypto = "0.2.34" elastic-array = "0.4" -heapsize = "0.3" +heapsize = { git = "https://github.com/nikvolf/heapsize" } itertools = "0.4" crossbeam = "0.2" slab = { git = "https://github.com/arkpar/slab.git" } From 8b4278aeaa2bb097c19ba77819cf5abdee72d4dd Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 18 Feb 2016 22:06:59 +0300 Subject: [PATCH 092/753] feature dep for heapsize --- .travis.yml | 1 + Cargo.lock | 7 +------ ethcore/Cargo.toml | 3 ++- util/Cargo.toml | 3 +++ 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index b2859589b..f7d3b6597 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ cache: - target/debug/build - target/release/deps - target/release/build + - $HOME/.cargo addons: apt: packages: diff --git a/Cargo.lock b/Cargo.lock index 05f674a69..ad2a13c92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,7 +175,7 @@ dependencies = [ "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", "ethcore-util 0.9.99", - "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.2 (git+https://github.com/nikvolf/heapsize)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -267,11 +267,6 @@ name = "heapsize" version = "0.3.2" source = "git+https://github.com/nikvolf/heapsize#7913872a4f928a49659df52e48dea69d8a2376bf" -[[package]] -name = "heapsize" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "hpack" version = "0.2.0" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index d8df6455a..6eb9dec22 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -11,7 +11,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" rocksdb = "0.3" -heapsize = "0.3" +heapsize = { git = "https://github.com/nikvolf/heapsize" } rust-crypto = "0.2.34" time = "0.1" ethcore-util = { path = "../util" } @@ -27,3 +27,4 @@ jit = ["evmjit"] evm-debug = [] json-tests = [] test-heavy = [] +default = [ "heapsize/nightly" ] diff --git a/util/Cargo.toml b/util/Cargo.toml index ea618ed45..9e32aea06 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -6,6 +6,9 @@ name = "ethcore-util" version = "0.9.99" authors = ["Ethcore "] +[features] +default = [ "heapsize/nightly" ] + [dependencies] log = "0.3" env_logger = "0.3" From 031b15daabb9d671e72822c0df541236d32b2f20 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 18 Feb 2016 22:12:25 +0300 Subject: [PATCH 093/753] update cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ad2a13c92..08e1e8775 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "heapsize" version = "0.3.2" -source = "git+https://github.com/nikvolf/heapsize#7913872a4f928a49659df52e48dea69d8a2376bf" +source = "git+https://github.com/nikvolf/heapsize#a2d682fd4dcf11e2deeeb229ef2375354c15668b" [[package]] name = "hpack" From beb0da4ff4e064d592806722c839ec8784e8b5f7 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 18 Feb 2016 22:56:21 +0300 Subject: [PATCH 094/753] and adding actual dependency --- ethcore/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 6eb9dec22..207db69fc 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -25,6 +25,6 @@ lazy_static = "0.1" [features] jit = ["evmjit"] evm-debug = [] -json-tests = [] +json-tests = [ "heapsize/nightly" ] test-heavy = [] default = [ "heapsize/nightly" ] From 99600ba370680851519950058c22f594812a6849 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 18 Feb 2016 21:15:56 +0100 Subject: [PATCH 095/753] DB Test --- util/src/journaldb.rs | 2 +- util/src/kvdb.rs | 60 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 8d31f50eb..cfcff6ea4 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -62,7 +62,7 @@ impl JournalDB { let opts = DatabaseConfig { prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix }; - let backing = Database::open(opts, path).unwrap_or_else(|e| { + let backing = Database::open(&opts, path).unwrap_or_else(|e| { panic!("Error opening state db: {}", e); }); if !backing.is_empty() { diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index a5691bcba..ac6a45a4e 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -69,11 +69,11 @@ pub struct Database { impl Database { /// Open database with default settings. pub fn open_default(path: &str) -> Result { - Database::open(DatabaseConfig { prefix_size: None }, path) + Database::open(&DatabaseConfig { prefix_size: None }, path) } /// Open database file. Creates if it does not exist. - pub fn open(config: DatabaseConfig, path: &str) -> Result { + pub fn open(config: &DatabaseConfig, path: &str) -> Result { let mut opts = Options::new(); opts.set_max_open_files(256); opts.create_if_missing(true); @@ -148,3 +148,59 @@ impl Database { } +#[cfg(test)] +mod tests { + use hash::*; + use super::*; + use tests::helpers::RandomTempPath; + use std::str::FromStr; + use std::ops::Deref; + + fn test_db(config: &DatabaseConfig) { + let path = RandomTempPath::create_dir(); + let db = Database::open(config, path.as_path().to_str().unwrap()).unwrap(); + let key1 = H256::from_str("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); + let key2 = H256::from_str("03c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); + let key3 = H256::from_str("01c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); + + db.put(&key1, b"cat").unwrap(); + db.put(&key2, b"dog").unwrap(); + + assert_eq!(db.get(&key1).unwrap().unwrap().deref(), b"cat"); + + let contents: Vec<_> = db.iter().collect(); + assert_eq!(contents.len(), 2); + assert_eq!(&*contents[0].0, key1.deref()); + assert_eq!(&*contents[0].1, b"cat"); + assert_eq!(&*contents[1].0, key2.deref()); + assert_eq!(&*contents[1].1, b"dog"); + + db.delete(&key1).unwrap(); + assert!(db.get(&key1).unwrap().is_none()); + db.put(&key1, b"cat").unwrap(); + + let transaction = DBTransaction::new(); + transaction.put(&key3, b"elephant").unwrap(); + transaction.delete(&key1).unwrap(); + db.write(transaction).unwrap(); + assert!(db.get(&key1).unwrap().is_none()); + assert_eq!(db.get(&key3).unwrap().unwrap().deref(), b"elephant"); + + if config.prefix_size.is_some() { + assert_eq!(db.get_by_prefix(&key3).unwrap().deref(), b"elephant"); + assert_eq!(db.get_by_prefix(&key2).unwrap().deref(), b"dog"); + } + } + + #[test] + fn kvdb() { + let path = RandomTempPath::create_dir(); + let smoke = Database::open_default(path.as_path().to_str().unwrap()).unwrap(); + assert!(smoke.is_empty()); + test_db(&DatabaseConfig { prefix_size: None }); + test_db(&DatabaseConfig { prefix_size: Some(1) }); + test_db(&DatabaseConfig { prefix_size: Some(8) }); + test_db(&DatabaseConfig { prefix_size: Some(32) }); + } +} + From 68795ea031fefff148c011a58d9f5407f47e7889 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 18 Feb 2016 21:40:17 +0100 Subject: [PATCH 096/753] Fixed typos --- util/src/kvdb.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index ac6a45a4e..fa74553fb 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Key-Value store abstraction with rocksb backend. +//! Key-Value store abstraction with RocksDB backend. use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBVector, DBIterator, IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction}; @@ -30,7 +30,7 @@ impl DBTransaction { DBTransaction { batch: WriteBatch::new() } } - /// Insert a ket-value pair in the transaction. Any existing value value will be overwritten upon write. + /// Insert a key-value pair in the transaction. Any existing value value will be overwritten upon write. pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { self.batch.put(key, value) } @@ -106,7 +106,7 @@ impl Database { Ok(Database { db: db }) } - /// Insert a ket-value pair in the transaction. Any existing value value will be overwritten. + /// Insert a key-value pair in the transaction. Any existing value value will be overwritten. pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { self.db.put(key, value) } From cc5384fff51c052d3985976c8901dffef7cee874 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 18 Feb 2016 22:35:14 +0100 Subject: [PATCH 097/753] Get rid of lru_cache dependency --- ethash/Cargo.toml | 1 - ethash/src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 4bba71a14..da08b9f92 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -7,5 +7,4 @@ authors = ["arkpar , + recent: Option>, + prev_epoch: Option, + prev: Option>, +} + /// Lighy/Full cache manager pub struct EthashManager { - lights: Mutex>> + cache: Mutex, } impl EthashManager { /// Create a new new instance of ethash manager pub fn new() -> EthashManager { EthashManager { - lights: Mutex::new(LruCache::new(2)) + cache: Mutex::new(LightCache { + recent_epoch: None, + recent: None, + prev_epoch: None, + prev: None, + }), } } @@ -50,8 +61,24 @@ impl EthashManager { pub fn compute_light(&self, block_number: u64, header_hash: &H256, nonce: u64) -> ProofOfWork { let epoch = block_number / ETHASH_EPOCH_LENGTH; let light = { - let mut lights = self.lights.lock().unwrap(); - match lights.get_mut(&epoch).map(|l| l.clone()) { + let mut lights = self.cache.lock().unwrap(); + let light = match lights.recent_epoch.clone() { + Some(ref e) if *e == epoch => lights.recent.clone(), + _ => match lights.prev_epoch.clone() { + Some(e) if e == epoch => { + // swap + let t = lights.prev_epoch; + lights.prev_epoch = lights.recent_epoch; + lights.recent_epoch = t; + let t = lights.prev.clone(); + lights.prev = lights.recent.clone(); + lights.recent = t; + lights.recent.clone() + } + _ => None, + } + }; + match light { None => { let light = match Light::from_file(block_number) { Ok(light) => Arc::new(light), @@ -64,7 +91,8 @@ impl EthashManager { Arc::new(light) } }; - lights.insert(epoch, light.clone()); + lights.prev_epoch = mem::replace(&mut lights.recent_epoch, Some(epoch)); + lights.prev = mem::replace(&mut lights.recent, Some(light.clone())); light } Some(light) => light @@ -73,3 +101,19 @@ impl EthashManager { light.compute(header_hash, nonce) } } + +#[test] +fn test_lru() { + let ethash = EthashManager::new(); + let hash = [0u8; 32]; + ethash.compute_light(1, &hash, 1); + ethash.compute_light(50000, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 1); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0); + ethash.compute_light(1, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 0); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 1); + ethash.compute_light(70000, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 2); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0); +} From af8ba067951dd1ed4bc3b36803015012f1b2736f Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 18 Feb 2016 23:29:41 +0100 Subject: [PATCH 098/753] utils compilable in beta --- Cargo.lock | 120 ++++++++++++++++------------------ Cargo.toml | 1 - ethcore/src/lib.rs | 2 - util/Cargo.toml | 5 +- util/src/hash.rs | 9 --- util/src/lib.rs | 4 -- util/src/panics.rs | 25 ++++--- util/src/rlp/bytes.rs | 8 +-- util/src/rlp/untrusted_rlp.rs | 1 - util/src/uint.rs | 96 --------------------------- 10 files changed, 75 insertions(+), 196 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6cdb6f53f..236969732 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,7 +6,6 @@ dependencies = [ "ctrlc 1.0.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt_macros 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-rpc 0.9.99", @@ -20,7 +19,7 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -37,10 +36,10 @@ dependencies = [ [[package]] name = "aster" -version = "0.12.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -69,7 +68,7 @@ version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "regex-syntax 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -130,14 +129,6 @@ dependencies = [ "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "docopt_macros" -version = "0.6.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "elastic-array" version = "0.4.0" @@ -155,14 +146,14 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.4" -source = "git+https://github.com/arkpar/rust-secp256k1.git#321e6c22a83606d1875f89cb61c9cb37c7d249ae" +source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -171,7 +162,6 @@ name = "ethash" version = "0.9.99" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lru-cache 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", ] @@ -179,6 +169,7 @@ dependencies = [ name = "ethcore" version = "0.9.99" dependencies = [ + "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", @@ -197,18 +188,15 @@ dependencies = [ name = "ethcore-rpc" version = "0.9.99" dependencies = [ -<<<<<<< HEAD -======= "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> rustup "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", "jsonrpc-core 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -219,10 +207,7 @@ name = "ethcore-util" version = "0.9.99" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -<<<<<<< HEAD -======= "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> rustup "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -238,7 +223,7 @@ dependencies = [ "rocksdb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.1.4 (git+https://github.com/arkpar/slab.git)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -250,10 +235,7 @@ dependencies = [ name = "ethsync" version = "0.9.99" dependencies = [ -<<<<<<< HEAD -======= "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ->>>>>>> rustup "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", @@ -367,8 +349,8 @@ name = "jsonrpc-core" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -416,11 +398,6 @@ name = "libc" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "linked-hash-map" -version = "0.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "log" version = "0.3.5" @@ -429,14 +406,6 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "lru-cache" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "linked-hash-map 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "matches" version = "0.1.2" @@ -456,7 +425,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -522,7 +491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -546,20 +515,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quasi" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quasi_codegen" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -575,7 +544,7 @@ name = "regex" version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -613,7 +582,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc_version" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", @@ -626,7 +595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "semver" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nom 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -634,22 +603,22 @@ dependencies = [ [[package]] name = "serde" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_codegen" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -657,8 +626,8 @@ name = "serde_json" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -700,6 +669,14 @@ dependencies = [ "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syntex" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syntex_syntax" version = "0.28.0" @@ -713,6 +690,19 @@ dependencies = [ "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syntex_syntax" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "target_info" version = "0.1.0" @@ -757,7 +747,7 @@ name = "unicase" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc_version 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8b9924a54..6ffc3d2b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" docopt = "0.6" -docopt_macros = "0.6" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } clippy = { version = "0.0.42", optional = true } ethcore-util = { path = "util" } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 093906bd0..8c9fcaff1 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -15,8 +15,6 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![feature(cell_extras)] -#![feature(augmented_assignments)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] // TODO [todr] not really sure diff --git a/util/Cargo.toml b/util/Cargo.toml index 25626780f..ff3fbc5dc 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -6,9 +6,6 @@ name = "ethcore-util" version = "0.9.99" authors = ["Ethcore "] -[features] -default = [ "heapsize/nightly" ] - [dependencies] log = "0.3" env_logger = "0.3" @@ -36,4 +33,4 @@ igd = "0.4.2" [features] default = [] -dev = ["clippy"] \ No newline at end of file +dev = ["clippy"] diff --git a/util/src/hash.rs b/util/src/hash.rs index 2e6c565b4..924465e70 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -413,15 +413,6 @@ macro_rules! impl_hash { } } - /// Moving BitOrAssign - impl<'a> BitOrAssign<&'a $from> for $from { - fn bitor_assign(&mut self, rhs: &'a Self) { - for i in 0..$size { - self.0[i] = self.0[i] | rhs.0[i]; - } - } - } - /// BitAnd on references impl <'a> BitAnd for &'a $from { type Output = $from; diff --git a/util/src/lib.rs b/util/src/lib.rs index 0a2b0f4b4..ef76bb885 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -15,12 +15,8 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![feature(op_assign_traits)] -#![feature(augmented_assignments)] -#![feature(associated_consts)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] -#![feature(catch_panic)] // Clippy settings // TODO [todr] not really sure #![allow(needless_range_loop)] diff --git a/util/src/panics.rs b/util/src/panics.rs index 27dd605f0..bc22282d2 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -40,6 +40,18 @@ pub trait MayPanic { fn on_panic(&self, closure: F) where F: OnPanicListener; } +struct PanicGuard<'a> { + handler: &'a PanicHandler, +} + +impl<'a> Drop for PanicGuard<'a> { + fn drop(&mut self) { + if thread::panicking() { + self.handler.notify_all("Panic!".to_owned()); + } + } +} + /// Structure that allows to catch panics and notify listeners pub struct PanicHandler { listeners: Mutex>> @@ -63,16 +75,9 @@ impl PanicHandler { #[allow(deprecated)] // TODO [todr] catch_panic is deprecated but panic::recover has different bounds (not allowing mutex) pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { - let result = thread::catch_panic(g); - - if let Err(ref e) = result { - let res = convert_to_string(e); - if let Some(r) = res { - self.notify_all(r); - } - } - - result + let guard = PanicGuard { handler: self }; + let result = g(); + Ok(result) } fn notify_all(&self, r: String) { diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs index 3b25c09ae..305ec9088 100644 --- a/util/src/rlp/bytes.rs +++ b/util/src/rlp/bytes.rs @@ -232,12 +232,12 @@ impl_uint_from_bytes!(u64); impl_uint_from_bytes!(usize); macro_rules! impl_uint_from_bytes { - ($name: ident) => { + ($name: ident, $size: expr) => { impl FromBytes for $name { fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { if !bytes.is_empty() && bytes[0] == 0 { Err(FromBytesError::ZeroPrefixedInt) - } else if bytes.len() <= $name::SIZE { + } else if bytes.len() <= $size { Ok($name::from(bytes)) } else { Err(FromBytesError::DataIsTooLong) @@ -247,8 +247,8 @@ macro_rules! impl_uint_from_bytes { } } -impl_uint_from_bytes!(U256); -impl_uint_from_bytes!(U128); +impl_uint_from_bytes!(U256, 256); +impl_uint_from_bytes!(U128, 128); impl FromBytes for T where T: FixedHash { fn from_bytes(bytes: &[u8]) -> FromBytesResult { diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 463d5cb2f..957a09b61 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -429,7 +429,6 @@ impl Decodable for Option where T: Decodable { macro_rules! impl_array_decodable { ($index_type:ty, $len:expr ) => ( impl Decodable for [T; $len] where T: Decodable { - #[allow(len_zero)] fn decode(decoder: &D) -> Result where D: Decoder { let decoders = decoder.as_rlp(); diff --git a/util/src/uint.rs b/util/src/uint.rs index b3427f6bc..912088fb9 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -78,9 +78,6 @@ macro_rules! panic_on_overflow { /// Large, fixed-length unsigned integer type. pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { - /// Size of this type. - const SIZE: usize; - /// Returns new instance equalling zero. fn zero() -> Self; /// Returns new instance equalling one. @@ -148,8 +145,6 @@ macro_rules! construct_uint { pub struct $name(pub [u64; $n_words]); impl Uint for $name { - const SIZE: usize = $n_words * 8; - type FromDecStrErr = FromHexError; /// TODO: optimize, throw appropriate err @@ -634,66 +629,6 @@ macro_rules! construct_uint { // TODO: optimise and traitify. - impl<'a> AddAssign<&'a $name> for $name { - fn add_assign(&mut self, other: &'a Self) { - *self = self.add(*other); - } - } - - impl<'a> SubAssign<&'a $name> for $name { - fn sub_assign(&mut self, other: &'a Self) { - *self = self.sub(*other); - } - } - - impl<'a> MulAssign<&'a $name> for $name { - fn mul_assign(&mut self, other: &'a Self) { - *self = self.mul(*other); - } - } - - impl<'a> DivAssign<&'a $name> for $name { - fn div_assign(&mut self, other: &'a Self) { - *self = self.div(*other); - } - } - - impl<'a> RemAssign<&'a $name> for $name { - fn rem_assign(&mut self, other: &'a Self) { - *self = self.rem(*other); - } - } - - impl AddAssign<$name> for $name { - fn add_assign(&mut self, other: Self) { - *self = self.add(other); - } - } - - impl SubAssign<$name> for $name { - fn sub_assign(&mut self, other: Self) { - *self = self.sub(other); - } - } - - impl MulAssign<$name> for $name { - fn mul_assign(&mut self, other: Self) { - *self = self.mul(other); - } - } - - impl DivAssign<$name> for $name { - fn div_assign(&mut self, other: Self) { - *self = self.div(other); - } - } - - impl RemAssign<$name> for $name { - fn rem_assign(&mut self, other: Self) { - *self = self.rem(other); - } - } - impl BitAnd<$name> for $name { type Output = $name; @@ -964,37 +899,6 @@ mod tests { use uint::{Uint, U128, U256, U512}; use std::str::FromStr; - #[test] - pub fn assign_ops() { - let x: U256 = x!(69); - let y: U256 = x!(42); - { - let mut z = x; - z += y; - assert_eq!(z, x + y); - } - { - let mut z = x; - z -= y; - assert_eq!(z, x - y); - } - { - let mut z = x; - z *= y; - assert_eq!(z, x * y); - } - { - let mut z = x; - z /= y; - assert_eq!(z, x / y); - } - { - let mut z = x; - z %= y; - assert_eq!(z, x % y); - } - } - #[test] pub fn uint256_from() { let e = U256([10, 0, 0, 0]); From df3d17789a0c835e994ea69b53cb04eba979637e Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 00:06:06 +0100 Subject: [PATCH 099/753] compiling ethcore on beta --- Cargo.lock | 6 +++--- ethcore/Cargo.toml | 6 +++--- ethcore/src/block.rs | 2 +- ethcore/src/client.rs | 2 +- ethcore/src/evm/interpreter.rs | 4 ++-- ethcore/src/lib.rs | 1 - ethcore/src/receipt.rs | 2 +- ethcore/src/state.rs | 13 ++++++------- util/Cargo.toml | 2 +- 9 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 236969732..b21fb1d63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", "ethcore-util 0.9.99", - "heapsize 0.3.2 (git+https://github.com/nikvolf/heapsize)", + "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -212,7 +212,7 @@ dependencies = [ "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", - "heapsize 0.3.2 (git+https://github.com/nikvolf/heapsize)", + "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", @@ -264,7 +264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "heapsize" version = "0.3.2" -source = "git+https://github.com/nikvolf/heapsize#a2d682fd4dcf11e2deeeb229ef2375354c15668b" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hpack" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index dee169c7e..090280cae 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -11,7 +11,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" rocksdb = "0.3" -heapsize = { git = "https://github.com/nikvolf/heapsize" } +heapsize = "0.3" rust-crypto = "0.2.34" time = "0.1" ethcore-util = { path = "../util" } @@ -25,7 +25,7 @@ lazy_static = "0.1" [features] jit = ["evmjit"] evm-debug = [] -json-tests = [ "heapsize/nightly" ] +json-tests = [] test-heavy = [] dev = ["clippy"] -default = [ "heapsize/nightly" ] +default = [] diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index c03417dc1..b646c4cde 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -267,7 +267,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> { s.block.base.header.uncles_hash = uncle_bytes.sha3(); s.block.base.header.state_root = s.block.state.root().clone(); s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|ref r| r.rlp_bytes().to_vec()).collect()); - s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b |= &r.log_bloom; b}); + s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b}); s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used); s.block.base.header.note_dirty(); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 09f7417e8..72e520ad7 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -162,7 +162,7 @@ impl ClientReport { pub fn accrue_block(&mut self, block: &PreVerifiedBlock) { self.blocks_imported += 1; self.transactions_applied += block.transactions.len(); - self.gas_processed += block.header.gas_used; + self.gas_processed = self.gas_processed + block.header.gas_used; } } diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index 50c0377ac..c04b7e1a9 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -299,7 +299,7 @@ impl evm::Evm for Interpreter { let (gas_cost, mem_size) = try!(self.get_gas_cost_mem(ext, instruction, &mut mem, &stack)); try!(self.verify_gas(¤t_gas, &gas_cost)); mem.expand(mem_size); - current_gas -= gas_cost; + current_gas = current_gas - gas_cost; evm_debug!({ println!("[0x{:x}][{}(0x{:x}) Gas: {:x}\n Gas Before: {:x}", @@ -320,7 +320,7 @@ impl evm::Evm for Interpreter { match result { InstructionResult::Ok => {}, InstructionResult::UnusedGas(gas) => { - current_gas += gas; + current_gas = current_gas + gas; }, InstructionResult::UseAllGas => { current_gas = U256::zero(); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 8c9fcaff1..11d129f61 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -24,7 +24,6 @@ // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![allow(clone_on_copy)] - //! Ethcore library //! //! ### Rust version: diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index 5fc1a318b..cd1897535 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -39,7 +39,7 @@ impl Receipt { Receipt { state_root: state_root, gas_used: gas_used, - log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b |= &l.bloom(); b }), + log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b = b | l.bloom(); b }), logs: logs, } } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 00886b89c..3eaedb9bf 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -282,7 +282,7 @@ impl State { /// Pull account `a` in our cache from the trie DB and return it. /// `require_code` requires that the code be cached, too. - fn get(&self, a: &Address, require_code: bool) -> Ref> { + fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option { let have_key = self.cache.borrow().contains_key(a); if !have_key { self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(Account::from_rlp)) @@ -292,17 +292,17 @@ impl State { account.cache_code(&AccountDB::new(&self.db, a)); } } - Ref::map(self.cache.borrow(), |m| m.get(a).unwrap()) + unsafe { ::std::mem::transmute(self.cache.borrow().get(a).unwrap()) } } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. - fn require(&self, a: &Address, require_code: bool) -> RefMut { + fn require<'a>(&'a self, a: &Address, require_code: bool) -> &'a mut Account { self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce), |_|{}) } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// If it doesn't exist, make account equal the evaluation of `default`. - fn require_or_from Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> RefMut { + fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account { let have_key = self.cache.borrow().contains_key(a); if !have_key { self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(Account::from_rlp)) @@ -316,13 +316,12 @@ impl State { not_default(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().unwrap()); } - let b = self.cache.borrow_mut(); - RefMut::map(b, |m| m.get_mut(a).unwrap().as_mut().map(|account| { + unsafe { ::std::mem::transmute(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().map(|account| { if require_code { account.cache_code(&AccountDB::new(&self.db, a)); } account - }).unwrap()) + }).unwrap()) } } } diff --git a/util/Cargo.toml b/util/Cargo.toml index ff3fbc5dc..18e9a0a75 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "0.1" eth-secp256k1 = { git = "https://github.com/arkpar/rust-secp256k1.git" } rust-crypto = "0.2.34" elastic-array = "0.4" -heapsize = { git = "https://github.com/nikvolf/heapsize" } +heapsize = "0.3" itertools = "0.4" crossbeam = "0.2" slab = { git = "https://github.com/arkpar/slab.git" } From 8fa62130e3548614452d22f22f6fb45409ab1815 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 00:23:05 +0100 Subject: [PATCH 100/753] Added TODOs --- ethcore/src/block.rs | 2 +- ethcore/src/evm/interpreter.rs | 4 ++-- ethcore/src/receipt.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index b646c4cde..d72fbd1ae 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -267,7 +267,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> { s.block.base.header.uncles_hash = uncle_bytes.sha3(); s.block.base.header.state_root = s.block.state.root().clone(); s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|ref r| r.rlp_bytes().to_vec()).collect()); - s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b}); + s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b}); //TODO: use |= operator s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used); s.block.base.header.note_dirty(); diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index c04b7e1a9..7efd79d00 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -299,7 +299,7 @@ impl evm::Evm for Interpreter { let (gas_cost, mem_size) = try!(self.get_gas_cost_mem(ext, instruction, &mut mem, &stack)); try!(self.verify_gas(¤t_gas, &gas_cost)); mem.expand(mem_size); - current_gas = current_gas - gas_cost; + current_gas = current_gas - gas_cost; //TODO: use operator -= evm_debug!({ println!("[0x{:x}][{}(0x{:x}) Gas: {:x}\n Gas Before: {:x}", @@ -320,7 +320,7 @@ impl evm::Evm for Interpreter { match result { InstructionResult::Ok => {}, InstructionResult::UnusedGas(gas) => { - current_gas = current_gas + gas; + current_gas = current_gas + gas; //TODO: use operator += }, InstructionResult::UseAllGas => { current_gas = U256::zero(); diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index cd1897535..59c842cd4 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -39,7 +39,7 @@ impl Receipt { Receipt { state_root: state_root, gas_used: gas_used, - log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b = b | l.bloom(); b }), + log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b = &b | &l.bloom(); b }), //TODO: use |= operator logs: logs, } } From 19a3daf533ebf223951dbbe41cc51e8ff70a6715 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 00:50:23 +0100 Subject: [PATCH 101/753] parity compiling fine --- Cargo.lock | 31 +++++-------------------------- parity/main.rs | 2 +- rpc/Cargo.toml | 2 +- sync/src/lib.rs | 4 ++-- sync/src/tests/helpers.rs | 5 ++++- 5 files changed, 13 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b21fb1d63..b69736c2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,13 +192,13 @@ dependencies = [ "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", - "jsonrpc-core 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -346,13 +346,13 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -361,7 +361,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -661,14 +661,6 @@ name = "strsim" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "syntex" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_syntax 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syntex" version = "0.29.0" @@ -677,19 +669,6 @@ dependencies = [ "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syntex_syntax" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syntex_syntax" version = "0.29.0" diff --git a/parity/main.rs b/parity/main.rs index 4238a9333..3279e1fed 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -17,7 +17,7 @@ //! Ethcore client application. #![warn(missing_docs)] -#![feature(plugin)] +#![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] extern crate docopt; extern crate rustc_serialize; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index f179b0c66..5e25b7901 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -23,7 +23,7 @@ serde_macros = { version = "0.6.13", optional = true } [build-dependencies] serde_codegen = { "version" = "0.6.13", "optional" = true } -syntex = "0.28.0" +syntex = "0.29.0" [features] default = ["serde_codegen"] diff --git a/sync/src/lib.rs b/sync/src/lib.rs index e80a89e50..2be662b65 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -17,7 +17,7 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] -#![feature(augmented_assignments)] +//#![feature(augmented_assignments)] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![allow(clone_on_copy)] @@ -59,7 +59,7 @@ use std::ops::*; use std::sync::*; use ethcore::client::Client; use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId}; -use util::io::TimerToken; +use util::TimerToken; use chain::ChainSync; use ethcore::service::SyncMessage; use io::NetSyncIo; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index c561b65a3..8c8b3b10a 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -213,7 +213,10 @@ impl BlockChainClient for TestBlockChainClient { } let len = self.numbers.read().unwrap().len(); if number == len { - *self.difficulty.write().unwrap().deref_mut() += header.difficulty; + { + let mut difficulty = self.difficulty.write().unwrap(); + *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; + } mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); self.blocks.write().unwrap().insert(h.clone(), b); self.numbers.write().unwrap().insert(number, h.clone()); From c0aca706d25e9769fdafff8241e7c00a1365fe24 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 00:51:17 +0100 Subject: [PATCH 102/753] removed commented out line --- sync/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 2be662b65..d6bce2447 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -17,7 +17,6 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] -//#![feature(augmented_assignments)] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![allow(clone_on_copy)] From 1486b7e6a090c76c0858df49c5dad2072df5dfbf Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 00:55:57 +0100 Subject: [PATCH 103/753] add beta to build matrix --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0d27ff239..b08e65cf3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ branches: matrix: fast_finish: true include: + - rust: beta + env: FEATURES='--features "ethcore/json-tests dev"' KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: nightly env: FEATURES='--features "ethcore/json-tests dev"' KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: From f45b2f9a243861f175b9d5e1ea090ae5cfe551aa Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 01:13:00 +0100 Subject: [PATCH 104/753] .travis matrix fixes for rust beta --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b08e65cf3..5c8cbe1d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,12 +9,14 @@ branches: - /^beta$/ - /^stable$/ matrix: - fast_finish: true + fast_finish: false + allow_failures: + - rust: nightly include: - rust: beta - env: FEATURES='--features "ethcore/json-tests dev"' KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features 'ethcore/json-tests'" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: nightly - env: FEATURES='--features "ethcore/json-tests dev"' KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features 'ethcore/json-tests dev'" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: apt: true directories: @@ -50,7 +52,7 @@ after_success: | ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && - [ $TRAVIS_RUST_VERSION = nightly ] && + [ $TRAVIS_RUST_VERSION = beta ] && cargo doc --no-deps --verbose ${KCOV_FEATURES} ${TARGETS} && echo '' > target/doc/index.html && pip install --user ghp-import && From e3e84020f477d2668e5468d45c02e9779593ce23 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 01:25:06 +0100 Subject: [PATCH 105/753] travis-beta and travis-nightly feaetures --- .travis.yml | 4 ++-- Cargo.toml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c8cbe1d1..60435a1c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,9 @@ matrix: - rust: nightly include: - rust: beta - env: FEATURES="--features 'ethcore/json-tests'" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: nightly - env: FEATURES="--features 'ethcore/json-tests dev'" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-nightly" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: apt: true directories: diff --git a/Cargo.toml b/Cargo.toml index 6ffc3d2b2..5b59b26f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ daemonize = "0.2" default = ["rpc"] rpc = ["ethcore-rpc"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] +travis-beta = ["ethcore/json-tests"] +travis-nightly = ["ethcore/json-tests", "dev"] [[bin]] path = "parity/main.rs" From bef6d5f2a1f3c267ffc5f25f4f3d28f117ca9d49 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 10:51:17 +0100 Subject: [PATCH 106/753] fixed insecure rlp uint conversion, and failing json tests --- util/src/rlp/bytes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs index 305ec9088..2ff6281cc 100644 --- a/util/src/rlp/bytes.rs +++ b/util/src/rlp/bytes.rs @@ -247,8 +247,8 @@ macro_rules! impl_uint_from_bytes { } } -impl_uint_from_bytes!(U256, 256); -impl_uint_from_bytes!(U128, 128); +impl_uint_from_bytes!(U256, 32); +impl_uint_from_bytes!(U128, 16); impl FromBytes for T where T: FixedHash { fn from_bytes(bytes: &[u8]) -> FromBytesResult { From 2ad8f6bd747e2011c8d43b610fcf76c7d9be143a Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 11:03:02 +0100 Subject: [PATCH 107/753] do not run benches on travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 60435a1c6..6ab9a08b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: | script: - cargo build --release --verbose ${FEATURES} - cargo test --release --verbose ${FEATURES} ${TARGETS} -- cargo bench --no-run ${FEATURES} ${TARGETS} +#- cargo bench --no-run ${FEATURES} ${TARGETS} - tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity after_success: | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && From 8831e73d9842100071cb4fd0014a904ef0ed4fc3 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 11:05:39 +0100 Subject: [PATCH 108/753] ignore panic forwarding tests --- util/src/panics.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/src/panics.rs b/util/src/panics.rs index bc22282d2..6bd8fc1d6 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -116,6 +116,7 @@ fn convert_to_string(t: &Box) -> Option { } #[test] +#[ignore] // panic forwarding doesnt work on the same thread in beta fn should_notify_listeners_about_panic () { use std::sync::RwLock; // given @@ -132,6 +133,7 @@ fn should_notify_listeners_about_panic () { } #[test] +#[ignore] // panic forwarding doesnt work on the same thread in beta fn should_notify_listeners_about_panic_when_string_is_dynamic () { use std::sync::RwLock; // given @@ -169,6 +171,7 @@ fn should_notify_listeners_about_panic_in_other_thread () { } #[test] +#[ignore] // panic forwarding doesnt work on the same thread in beta fn should_forward_panics () { use std::sync::RwLock; // given From ba4c2c94ec96d433e1c62edff40f927cf08ed503 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 11:26:24 +0100 Subject: [PATCH 109/753] Update Cargo.toml --- rpc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 5e25b7901..0b7c17383 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -22,7 +22,7 @@ rustc-serialize = "0.3" serde_macros = { version = "0.6.13", optional = true } [build-dependencies] -serde_codegen = { "version" = "0.6.13", "optional" = true } +serde_codegen = { version = "0.6.13", optional = true } syntex = "0.29.0" [features] From a4846e4aad65be53c0f700af269ca05a74c9626f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 11:31:40 +0100 Subject: [PATCH 110/753] Update bytes.rs --- util/src/bytes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index a26804c5b..08c299ddf 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -141,7 +141,7 @@ impl<'a> Deref for BytesRef<'a> { fn deref(&self) -> &[u8] { match *self { BytesRef::Flexible(ref bytes) => bytes, - BytesRef::Fixed(ref bytes) => bytes + BytesRef::Fixed(ref bytes) => bytes, } } } @@ -150,7 +150,7 @@ impl <'a> DerefMut for BytesRef<'a> { fn deref_mut(&mut self) -> &mut [u8] { match *self { BytesRef::Flexible(ref mut bytes) => bytes, - BytesRef::Fixed(ref mut bytes) => bytes + BytesRef::Fixed(ref mut bytes) => bytes, } } } From 0e10efc727de63d6c0c5ccad4b3c032f9d909b8d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 11:33:46 +0100 Subject: [PATCH 111/753] Update blockchain.rs --- ethcore/src/blockchain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 052e64d4c..cfb057b19 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -35,7 +35,7 @@ pub struct TreeRoute { /// Best common ancestor of these blocks. pub ancestor: H256, /// An index where best common ancestor would be. - pub index: usize + pub index: usize, } /// Represents blockchain's in-memory cache size in bytes. From 4f6bff1c47d6be087638623e0b396140e6b51e65 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 11:39:36 +0100 Subject: [PATCH 112/753] Kill bad test. --- ethcore/src/service.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 5e68efae9..2fc246025 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -124,6 +124,8 @@ impl IoHandler for ClientIoHandler { } } +// TODO: rewrite into something that doesn't dependent on the testing environment having a particular port ready for use. +/* #[cfg(test)] mod tests { use super::*; @@ -138,3 +140,4 @@ mod tests { assert!(service.is_ok()); } } +*/ \ No newline at end of file From 33b649bb0174db2d60fd7d9325ced186d2cdb0b1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 11:57:04 +0100 Subject: [PATCH 113/753] Update script. --- install-deps.sh | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/install-deps.sh b/install-deps.sh index 774d18720..214b6748c 100755 --- a/install-deps.sh +++ b/install-deps.sh @@ -346,8 +346,7 @@ function run_installer() exe brew install rocksdb info "Installing multirust" exe brew install multirust - sudo multirust update nightly - sudo multirust default nightly + sudo multirust default beta echo } @@ -426,20 +425,20 @@ function run_installer() depFound=$((depFound+1)) check "multirust" isMultirust=true - if [[ $(multirust show-default 2>/dev/null | grep nightly | wc -l) == 4 ]]; then + if [[ $(multirust show-default 2>/dev/null | grep beta | wc -l) == 4 ]]; then depFound=$((depFound+1)) - check "rust nightly" - isMultirustNightly=true + check "rust beta" + isMultirustBeta=true else - uncheck "rust is not nightly" - isMultirustNightly=false - INSTALL_FILES+="${blue}${dim}==> multirust -> rust nightly:${reset}${n}" + uncheck "rust is not beta" + isMultirustBeta=false + INSTALL_FILES+="${blue}${dim}==> multirust -> rust beta:${reset}${n}" fi else uncheck "multirust is missing" - uncheck "rust nightly is missing" + uncheck "rust beta is missing" isMultirust=false - isMultirustNightly=false + isMultirustBeta=false INSTALL_FILES+="${blue}${dim}==> multirust:${reset}${n}" fi } @@ -626,10 +625,9 @@ function run_installer() echo fi - if [[ $isMultirustNightly == false ]]; then - info "Installing rust nightly..." - multirust update nightly - multirust default nightly + if [[ $isMultirustBeta == false ]]; then + info "Installing rust beta..." + multirust default beta echo fi } @@ -660,7 +658,7 @@ function run_installer() find_rocksdb find_multirust - if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isRocksDB == false || $isMultirustNightly == false ]]; then + if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isRocksDB == false || $isMultirustBeta == false ]]; then abort_install fi fi From f50bf528e6106960f8b8620eb59df195d1334a82 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 11:57:52 +0100 Subject: [PATCH 114/753] fixed allow warnings in util --- util/src/lib.rs | 9 +++++---- util/src/network/discovery.rs | 2 +- util/src/network/host.rs | 6 +++--- util/src/panics.rs | 2 +- util/src/trie/triedb.rs | 2 +- util/src/trie/triedbmut.rs | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/util/src/lib.rs b/util/src/lib.rs index ef76bb885..59713a107 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -17,15 +17,16 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] + // Clippy settings // TODO [todr] not really sure -#![allow(needless_range_loop)] +#![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![allow(match_bool)] +#![cfg_attr(feature="dev", allow(match_bool))] // We use that to be more explicit about handled cases -#![allow(match_same_arms)] +#![cfg_attr(feature="dev", allow(match_same_arms))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![allow(clone_on_copy)] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Ethcore-util library //! diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 3e914761d..e28c79e80 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -138,7 +138,7 @@ impl Discovery { ret } - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn nearest_node_entries<'b>(source: &NodeId, target: &NodeId, buckets: &'b [NodeBucket]) -> Vec<&'b NodeId> { // send ALPHA FindNode packets to nodes we know, closest to target diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 430850453..5db724d32 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -471,7 +471,7 @@ impl Host where Message: Send + Sync + Clone { } } - #[allow(single_match)] + #[cfg_attr(feature="dev", allow(single_match))] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { @@ -501,7 +501,7 @@ impl Host where Message: Send + Sync + Clone { self.create_connection(socket, Some(id), io); } - #[allow(block_in_if_condition_stmt)] + #[cfg_attr(feature="dev", allow(block_in_if_condition_stmt))] fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) { let nonce = self.info.write().unwrap().next_nonce(); let mut connections = self.connections.write().unwrap(); @@ -532,7 +532,7 @@ impl Host where Message: Send + Sync + Clone { io.update_registration(TCP_ACCEPT).expect("Error registering TCP listener"); } - #[allow(single_match)] + #[cfg_attr(feature="dev", allow(single_match))] fn connection_writable(&self, token: StreamToken, io: &IoContext>) { let mut create_session = false; let mut kill = false; diff --git a/util/src/panics.rs b/util/src/panics.rs index 6bd8fc1d6..18ed9ecb1 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -72,7 +72,7 @@ impl PanicHandler { /// Invoke closure and catch any possible panics. /// In case of panic notifies all listeners about it. - #[allow(deprecated)] + #[cfg_attr(feature="dev", allow(deprecated))] // TODO [todr] catch_panic is deprecated but panic::recover has different bounds (not allowing mutex) pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { let guard = PanicGuard { handler: self }; diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index e7884a177..c4b5e120c 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -54,7 +54,7 @@ pub struct TrieDB<'db> { pub hash_count: usize, } -#[allow(wrong_self_convention)] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDB<'db> { /// Create a new trie with the backing database `db` and `root` /// Panics, if `root` does not exist diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 8e92063aa..2b4567264 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -66,7 +66,7 @@ enum MaybeChanged<'a> { Changed(Bytes), } -#[allow(wrong_self_convention)] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDBMut<'db> { /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. @@ -350,7 +350,7 @@ impl<'db> TrieDBMut<'db> { } } - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Determine the RLP of the node, assuming we're inserting `partial` into the /// node currently of data `old`. This will *not* delete any hash of `old` from the database; /// it will just return the new RLP that includes the new node. From 1cd76de8baa970b7f529caea1e9bf166f5555b6f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 11:57:59 +0100 Subject: [PATCH 115/753] Update readme for betaUpdate readme for beta --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 40c8796e2..b840195d8 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,8 @@ apt-get install -y --force-yes librocksdb-dev # install multirust curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install nightly and make it default -multirust update nightly -multirust default nightly +# install beta and make it default +multirust default beta # download and build parity git clone https://github.com/ethcore/parity @@ -47,12 +46,11 @@ sudo cp -a librocksdb.so* /usr/lib sudo ldconfig cd .. -# install rust nightly +# install rust beta curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes -# install nightly and make it default -sudo multirust update nightly -sudo multirust default nightly +# install beta and make it default +sudo multirust default beta # download and build parity git clone https://github.com/ethcore/parity @@ -68,8 +66,8 @@ brew update brew install rocksdb brew install multirust -# install nightly and make it default -multirust update nightly && multirust default nightly +# install beta and make it default +multirust default beta # download and build parity git clone https://github.com/ethcore/parity From b5d6359030d5b832d913776796e3fe56ca719699 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 12:19:43 +0100 Subject: [PATCH 116/753] fixed allow warnings in ethcore --- ethcore/src/basic_types.rs | 2 +- ethcore/src/block.rs | 2 +- ethcore/src/block_queue.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/evm/interpreter.rs | 6 +++--- ethcore/src/externalities.rs | 2 +- ethcore/src/lib.rs | 8 +++++--- ethcore/src/service.rs | 4 ++-- ethcore/src/spec.rs | 2 +- ethcore/src/state.rs | 2 +- rpc/src/v1/types/block_number.rs | 5 ++--- sync/src/chain.rs | 4 ++-- sync/src/lib.rs | 3 ++- 13 files changed, 23 insertions(+), 21 deletions(-) diff --git a/ethcore/src/basic_types.rs b/ethcore/src/basic_types.rs index 2e9c5d7b9..5f6515c0d 100644 --- a/ethcore/src/basic_types.rs +++ b/ethcore/src/basic_types.rs @@ -24,7 +24,7 @@ pub type LogBloom = H2048; /// Constant 2048-bit datum for 0. Often used as a default. pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); -#[allow(enum_variant_names)] +#[cfg_attr(feature="dev", allow(enum_variant_names))] /// Semantic boolean for when a seal/signature is included. pub enum Seal { /// The seal/signature is included. diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d72fbd1ae..b7590143e 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -16,7 +16,7 @@ //! Blockchain block. -#![allow(ptr_arg)] // Because of &LastHashes -> &Vec<_> +#![cfg_attr(feature="dev", allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> use common::*; use engine::*; diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 1a1dee48e..851c56c05 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -87,7 +87,7 @@ struct QueueSignal { } impl QueueSignal { - #[allow(bool_comparison)] + #[cfg_attr(feature="dev", allow(bool_comparison))] fn set(&self) { if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false { self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message"); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index c45b22102..ff6c6ba72 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -206,7 +206,7 @@ impl Engine for Ethash { } } -#[allow(wrong_self_convention)] // to_ethash should take self +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // to_ethash should take self impl Ethash { fn calculate_difficuty(&self, header: &Header, parent: &Header) -> U256 { const EXP_DIFF_PERIOD: u64 = 100000; diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index 7efd79d00..e09c37319 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -243,7 +243,7 @@ struct CodeReader<'a> { code: &'a Bytes } -#[allow(len_without_is_empty)] +#[cfg_attr(feature="dev", allow(len_without_is_empty))] impl<'a> CodeReader<'a> { /// Get `no_of_bytes` from code and convert to U256. Move PC fn read(&mut self, no_of_bytes: usize) -> U256 { @@ -258,7 +258,7 @@ impl<'a> CodeReader<'a> { } } -#[allow(enum_variant_names)] +#[cfg_attr(feature="dev", allow(enum_variant_names))] enum InstructionCost { Gas(U256), GasMem(U256, U256), @@ -347,7 +347,7 @@ impl evm::Evm for Interpreter { } impl Interpreter { - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn get_gas_cost_mem(&self, ext: &evm::Ext, instruction: Instruction, diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 360bd9738..9116629fb 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -188,7 +188,7 @@ impl<'a> Ext for Externalities<'a> { self.state.code(address).unwrap_or_else(|| vec![]) } - #[allow(match_ref_pats)] + #[cfg_attr(feature="dev", allow(match_ref_pats))] fn ret(&mut self, gas: &U256, data: &[u8]) -> Result { match &mut self.output { &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 11d129f61..8e59cf7a2 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -17,12 +17,14 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] + +// Clippy config // TODO [todr] not really sure -#![allow(needless_range_loop)] +#![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![allow(match_bool)] +#![cfg_attr(feautre="dev", allow(match_bool))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![allow(clone_on_copy)] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Ethcore library //! diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 5e68efae9..d20959077 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -110,8 +110,8 @@ impl IoHandler for ClientIoHandler { } } - #[allow(match_ref_pats)] - #[allow(single_match)] + #[cfg_attr(feature="dev", allow(match_ref_pats))] + #[cfg_attr(feature="dev", allow(single_match))] fn message(&self, io: &IoContext, net_message: &NetSyncMessage) { if let &UserMessage(ref message) = net_message { match message { diff --git a/ethcore/src/spec.rs b/ethcore/src/spec.rs index 67269d334..5714ca734 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec.rs @@ -97,7 +97,7 @@ pub struct Spec { genesis_state: PodState, } -#[allow(wrong_self_convention)] // because to_engine(self) should be to_engine(&self) +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) impl Spec { /// Convert this object into a boxed Engine of the right underlying type. // TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead. diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 3eaedb9bf..bbec8cd37 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -224,7 +224,7 @@ impl State { /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. - #[allow(match_ref_pats)] + #[cfg_attr(feature="dev", allow(match_ref_pats))] pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { // first, commit the sub trees. // TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index 546816eba..bb563de99 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -55,13 +55,12 @@ impl Visitor for BlockNumberVisitor { } impl Into for BlockNumber { - #[allow(match_same_arms)] fn into(self) -> BlockId { match self { BlockNumber::Num(n) => BlockId::Number(n), BlockNumber::Earliest => BlockId::Earliest, - BlockNumber::Latest => BlockId::Latest, - BlockNumber::Pending => BlockId::Latest // TODO: change this once blockid support pending + // TODO: change this once blockid support pendingst, + BlockNumber::Pending | BlockNumber::Latest => BlockId::Latest, } } } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 1c830ba7e..00e677538 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -251,7 +251,7 @@ impl ChainSync { } - #[allow(for_kv_map)] // Because it's not possible to get `values_mut()` + #[cfg_attr(feature="dev", allow(for_kv_map))] // Because it's not possible to get `values_mut()` /// Rest sync. Clear all downloaded data but keep the queue fn reset(&mut self) { self.downloading_headers.clear(); @@ -319,7 +319,7 @@ impl ChainSync { Ok(()) } - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Called by peer once it has new block headers during sync fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index d6bce2447..fd586409a 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -17,8 +17,9 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] + // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![allow(clone_on_copy)] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Blockchain sync module //! Implements ethereum protocol version 63 as specified here: From 63c5a2e58f6a03835ad12690b58b3874be31f1a0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 19 Feb 2016 14:52:29 +0300 Subject: [PATCH 117/753] copy instead of ref-map --- util/src/keys/directory.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 9c01d1974..67bf8cbc1 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -473,7 +473,7 @@ impl KeyDirectory { /// Returns key given by id if corresponding file exists and no load error occured. /// Warns if any error occured during the key loading - pub fn get(&self, id: &Uuid) -> Option> { + pub fn get(&self, id: &Uuid) -> Option { let path = self.key_path(id); { let mut usage = self.cache_usage.borrow_mut(); @@ -492,7 +492,10 @@ impl KeyDirectory { } } - Some(Ref::map(self.cache.borrow(), |c| c.get(id).expect("should be they key, we have just inserted or checked it"))) + // todo: replace with Ref::map when it stabilized to avoid copies + Some(self.cache.borrow().get(id) + .expect("should be they key, we have just inserted or checked it") + .clone()) } /// Returns current path to the directory with keys From 2cc690f31f27adb5e761cc676d90b7c94c1afec9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 12:54:51 +0100 Subject: [PATCH 118/753] Better user errors. Fixed up README. --- Cargo.lock | 2 ++ Cargo.toml | 2 ++ README.md | 2 +- parity/main.rs | 64 ++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b69736c2e..34b618c2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,9 @@ dependencies = [ "ethcore-util 0.9.99", "ethsync 0.9.99", "fdlimit 0.1.0", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 5b59b26f1..f4163253b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" daemonize = "0.2" +regex = "0.1" +lazy_static = "0.1" [features] default = ["rpc"] diff --git a/README.md b/README.md index b840195d8..4e238fd6f 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ cd .. curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes # install beta and make it default -sudo multirust default beta +multirust default beta # download and build parity git clone https://github.com/ethcore/parity diff --git a/parity/main.rs b/parity/main.rs index 3279e1fed..aca2b9c03 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -26,17 +26,21 @@ extern crate ethcore; extern crate ethsync; #[macro_use] extern crate log as rlog; +#[macro_use] +extern crate lazy_static; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate target_info; extern crate daemonize; +extern crate regex; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; use std::net::{SocketAddr}; use std::env; +use std::process::exit; use rlog::{LogLevelFilter}; use env_logger::LogBuilder; use ctrlc::CtrlC; @@ -51,6 +55,7 @@ use ethsync::EthSync; use docopt::Docopt; use target_info::Target; use daemonize::Daemonize; +use regex::Regex; const USAGE: &'static str = " Parity. Ethereum Client. @@ -150,6 +155,16 @@ By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf.\ ", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()); } +fn die_with_message(msg: &str) -> ! { + println!("ERROR: {}", msg); + exit(1); +} + +#[macro_export] +macro_rules! die { + ($($arg:tt)*) => (die_with_message(&format!("{}", format_args!($($arg)*)))); +} + struct Configuration { args: Args } @@ -174,7 +189,17 @@ impl Configuration { "frontier" | "mainnet" => ethereum::new_frontier(), "morden" | "testnet" => ethereum::new_morden(), "olympic" => ethereum::new_olympic(), - f => Spec::from_json_utf8(contents(f).expect("Couldn't read chain specification file. Sure it exists?").as_ref()), + f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| die!("{}: Couldn't read chain specification file. Sure it exists?", f)).as_ref()), + } + } + + fn normalize_enode(e: &str) -> Option { + lazy_static! { + static ref RE: Regex = Regex::new(r"^enode://([0-9a-fA-F]{64})@(\d+\.\d+\.\d+\.\d+):(\d+)$").unwrap(); + } + match RE.is_match(e) { + true => Some(e.to_owned()), + false => None, } } @@ -182,7 +207,7 @@ impl Configuration { if self.args.flag_no_bootstrap { Vec::new() } else { match self.args.arg_enode.len() { 0 => spec.nodes().clone(), - _ => self.args.arg_enode.clone(), // TODO check format first. + _ => self.args.arg_enode.iter().map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s))).collect(), } } } @@ -197,7 +222,7 @@ impl Configuration { public_address = SocketAddr::from_str(self.args.flag_public_address.as_ref()).expect("Invalid public address given with --public-address"); } Some(ref a) => { - public_address = SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address"); + public_address = SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_|die!("{}: Invalid listen/public address given with --address", a)); listen_address = public_address; } }; @@ -205,17 +230,28 @@ impl Configuration { (listen_address, public_address) } + fn net_settings(&self, spec: &Spec) -> NetworkConfiguration { + let mut ret = NetworkConfiguration::new(); + ret.nat_enabled = self.args.flag_upnp; + ret.boot_nodes = self.init_nodes(spec); + let (listen, public) = self.net_addresses(); + ret.listen_address = listen; + ret.public_address = public; + ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.as_bytes().sha3())); + ret + } + fn execute(&self) { if self.args.flag_version { print_version(); return; } if self.args.cmd_daemon { - let daemonize = Daemonize::new().pid_file(self.args.arg_pid_file.clone()).chown_pid_file(true); - match daemonize.start() { - Ok(_) => info!("Daemonized"), - Err(e) => { error!("{}", e); return; }, - } + Daemonize::new() + .pid_file(self.args.arg_pid_file.clone()) + .chown_pid_file(true) + .start() + .unwrap_or_else(|e| die!("Couldn't daemonize; {}", e)); } self.execute_client(); } @@ -227,15 +263,7 @@ impl Configuration { unsafe { ::fdlimit::raise_fd_limit(); } let spec = self.spec(); - - // Configure network - let mut net_settings = NetworkConfiguration::new(); - net_settings.nat_enabled = self.args.flag_upnp; - net_settings.boot_nodes = self.init_nodes(&spec); - let (listen, public) = self.net_addresses(); - net_settings.listen_address = listen; - net_settings.public_address = public; - net_settings.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); + let net_settings = self.net_settings(&spec); // Build client let mut service = ClientService::start(spec, net_settings, &Path::new(&self.path())).unwrap(); @@ -265,11 +293,13 @@ impl Configuration { fn wait_for_exit(client_service: &ClientService) { let exit = Arc::new(Condvar::new()); + // Handle possible exits let e = exit.clone(); CtrlC::set_handler(move || { e.notify_all(); }); let e = exit.clone(); client_service.on_panic(move |_reason| { e.notify_all(); }); + // Wait for signal let mutex = Mutex::new(()); let _ = exit.wait(mutex.lock().unwrap()).unwrap(); From fe979f0d46c5d5be41ff3dc71f1a83bc9e71c249 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 19 Feb 2016 15:21:52 +0300 Subject: [PATCH 119/753] [ci skip] update readme with rust override --- README.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b840195d8..29f634c16 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,17 @@ apt-get install -y --force-yes librocksdb-dev # install multirust curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install beta and make it default -multirust default beta +# install beta +multirust update beta # download and build parity git clone https://github.com/ethcore/parity cd parity + +# parity should be build with rust beta +multirust override beta + +# build in release cargo build --release ``` @@ -49,12 +54,17 @@ cd .. # install rust beta curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes -# install beta and make it default -sudo multirust default beta +# install rust beta +sudo multirust update beta # download and build parity git clone https://github.com/ethcore/parity cd parity + +# parity should be build with rust beta +sudo multirust override beta + +# build in release cargo build --release ``` @@ -66,12 +76,16 @@ brew update brew install rocksdb brew install multirust -# install beta and make it default -multirust default beta +# install beta +multirust update beta # download and build parity git clone https://github.com/ethcore/parity cd parity + +# use rust beta for building parity +multirust override beta + cargo build --release ``` From d43b23d663ccb401352efbd8854745b1ecadf079 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 13:30:36 +0100 Subject: [PATCH 120/753] Update directory.rs --- util/src/keys/directory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 67bf8cbc1..23c483482 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -494,7 +494,7 @@ impl KeyDirectory { // todo: replace with Ref::map when it stabilized to avoid copies Some(self.cache.borrow().get(id) - .expect("should be they key, we have just inserted or checked it") + .expect("Key should be there, we have just inserted or checked it.") .clone()) } From 85c842b7fd52c08215ff09eca88d28db18eba103 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 13:47:13 +0100 Subject: [PATCH 121/753] Restored service test --- ethcore/src/service.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 9389f1db1..db0260b06 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -124,8 +124,6 @@ impl IoHandler for ClientIoHandler { } } -// TODO: rewrite into something that doesn't dependent on the testing environment having a particular port ready for use. -/* #[cfg(test)] mod tests { use super::*; @@ -136,8 +134,7 @@ mod tests { fn it_can_be_started() { let spec = get_test_spec(); let temp_path = RandomTempPath::new(); - let service = ClientService::start(spec, NetworkConfiguration::new(), &temp_path.as_path()); + let service = ClientService::start(spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path()); assert!(service.is_ok()); } } -*/ \ No newline at end of file From beab90c70715aaddf6c325e40aa8f125d062a4ef Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 14:13:20 +0100 Subject: [PATCH 122/753] Added is_valid_node_url --- util/src/network/mod.rs | 1 + util/src/network/node_table.rs | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index ff52212af..50645f2be 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -89,6 +89,7 @@ pub use network::host::NetworkConfiguration; pub use network::stats::NetworkStats; use io::TimerToken; +pub use network::node_table::is_valid_node_url; const PROTOCOL_VERSION: u32 = 4; diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index 065990a63..f528f7134 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -332,6 +332,11 @@ impl Drop for NodeTable { } } +pub fn is_valid_node_url(url: &str) -> bool { + use std::str::FromStr; + Node::from_str(url).is_ok() +} + #[cfg(test)] mod tests { use super::*; @@ -353,6 +358,7 @@ mod tests { #[test] fn node_parse() { + assert!(is_valid_node_url("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770")); let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); assert!(node.is_ok()); let node = node.unwrap(); From ec428c070bc27925265c568f129a7a7dc92e0a24 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 14:17:04 +0100 Subject: [PATCH 123/753] added trailing , --- ethcore/src/extras.rs | 6 +++--- ethcore/src/filter.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index 50d3a21bf..c7102dba9 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -35,7 +35,7 @@ pub enum ExtrasIndex { /// Block blooms index BlocksBlooms = 4, /// Block receipts index - BlockReceipts + BlockReceipts = 5, } /// trait used to write Extras data to db @@ -213,7 +213,7 @@ impl Encodable for BlockLogBlooms { /// Neighboring log blooms on certain level pub struct BlocksBlooms { /// List of block blooms. - pub blooms: [H2048; 16] + pub blooms: [H2048; 16], } impl BlocksBlooms { @@ -269,7 +269,7 @@ pub struct BlocksBloomLocation { /// Unique hash of BlocksBloom pub hash: H256, /// Index within BlocksBloom - pub index: usize + pub index: usize, } /// Represents address of certain transaction within block diff --git a/ethcore/src/filter.rs b/ethcore/src/filter.rs index 5daecebd3..f5f9135d6 100644 --- a/ethcore/src/filter.rs +++ b/ethcore/src/filter.rs @@ -39,7 +39,7 @@ pub struct Filter { /// /// If None, match all. /// If specified, log must contain one of these topics. - pub topics: [Option>; 4] + pub topics: [Option>; 4], } impl Filter { From 2f62994f61247c4a94f70b1c9a908e9fbd67860a Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 15:17:31 +0100 Subject: [PATCH 124/753] Updated cargo.lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d0a31352..97ec5f386 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -400,7 +400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librocksdb-sys" version = "0.1.0" -source = "git+https://github.com/arkpar/rust-rocksdb.git#31d2761f5132222f5277c8c0c31b0b55b65e0bee" +source = "git+https://github.com/arkpar/rust-rocksdb.git#a745277de9848a1ce374fee037a3cf3cacdf9b67" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -571,7 +571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" version = "0.3.0" -source = "git+https://github.com/arkpar/rust-rocksdb.git#31d2761f5132222f5277c8c0c31b0b55b65e0bee" +source = "git+https://github.com/arkpar/rust-rocksdb.git#a745277de9848a1ce374fee037a3cf3cacdf9b67" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "librocksdb-sys 0.1.0 (git+https://github.com/arkpar/rust-rocksdb.git)", From fed90c126ec80ba67fb3d6b16338866dc320de14 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 19 Feb 2016 17:18:20 +0300 Subject: [PATCH 125/753] dev/test tools to separate crate --- devtools/Cargo.toml | 16 + devtools/LICENSE.txt | 675 ++++++++++++++++++++++++++++++++ devtools/README.md | 1 + devtools/src/lib.rs | 24 ++ devtools/src/random_path.rs | 71 ++++ ethcore/Cargo.toml | 3 + ethcore/src/blockchain.rs | 5 +- ethcore/src/json_tests/chain.rs | 1 + ethcore/src/lib.rs | 1 + ethcore/src/state.rs | 3 +- ethcore/src/tests/client.rs | 1 + ethcore/src/tests/helpers.rs | 34 +- util/Cargo.toml | 4 + util/src/keys/directory.rs | 4 +- util/src/keys/store.rs | 4 +- util/src/lib.rs | 4 +- util/src/tests/helpers.rs | 31 -- util/src/tests/mod.rs | 1 - 18 files changed, 809 insertions(+), 74 deletions(-) create mode 100644 devtools/Cargo.toml create mode 100644 devtools/LICENSE.txt create mode 100644 devtools/README.md create mode 100644 devtools/src/lib.rs create mode 100644 devtools/src/random_path.rs delete mode 100644 util/src/tests/helpers.rs delete mode 100644 util/src/tests/mod.rs diff --git a/devtools/Cargo.toml b/devtools/Cargo.toml new file mode 100644 index 000000000..ce0260936 --- /dev/null +++ b/devtools/Cargo.toml @@ -0,0 +1,16 @@ +[package] +description = "Ethcore development/test/build tools" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "ethcore-devtools" +version = "0.9.99" +authors = ["Ethcore "] + +[dependencies] +rand = "0.3" + +[features] + +[lib] +path = "src/lib.rs" +test = true diff --git a/devtools/LICENSE.txt b/devtools/LICENSE.txt new file mode 100644 index 000000000..733c07236 --- /dev/null +++ b/devtools/LICENSE.txt @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program 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. + + This program 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 this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/devtools/README.md b/devtools/README.md new file mode 100644 index 000000000..5d5144689 --- /dev/null +++ b/devtools/README.md @@ -0,0 +1 @@ +# ethcore dev tools diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs new file mode 100644 index 000000000..f310cca30 --- /dev/null +++ b/devtools/src/lib.rs @@ -0,0 +1,24 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! dev-tools + + +extern crate rand; + +pub mod random_path; + +pub use random_path::*; diff --git a/devtools/src/random_path.rs b/devtools/src/random_path.rs new file mode 100644 index 000000000..3cbd19b96 --- /dev/null +++ b/devtools/src/random_path.rs @@ -0,0 +1,71 @@ +use std::path::*; +use std::fs; +use std::env; +use rand::random; + +pub struct RandomTempPath { + path: PathBuf +} + +pub fn random_filename() -> String { + (0..8).map(|_| ((random::() * 26.0) as u8 + 97) as char).collect() +} + +impl RandomTempPath { + pub fn new() -> RandomTempPath { + let mut dir = env::temp_dir(); + dir.push(random_filename()); + RandomTempPath { + path: dir.clone() + } + } + + pub fn create_dir() -> RandomTempPath { + let mut dir = env::temp_dir(); + dir.push(random_filename()); + fs::create_dir_all(dir.as_path()).unwrap(); + RandomTempPath { + path: dir.clone() + } + } + + pub fn as_path(&self) -> &PathBuf { + &self.path + } + + pub fn as_str(&self) -> &str { + self.path.to_str().unwrap() + } +} + +impl Drop for RandomTempPath { + fn drop(&mut self) { + if let Err(e) = fs::remove_dir_all(self.as_path()) { + panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); + } + } +} + +#[test] +fn creates_dir() { + let temp = RandomTempPath::create_dir(); + assert!(fs::metadata(temp.as_path()).unwrap().is_dir()); +} + +#[test] +fn destroys_dir() { + let path_buf = { + let temp = RandomTempPath::create_dir(); + assert!(fs::metadata(temp.as_path()).unwrap().is_dir()); + let path_buf = temp.as_path().to_path_buf(); + path_buf + }; + + assert!(fs::metadata(&path_buf).is_err()); +} + +#[test] +fn provides_random() { + let temp = RandomTempPath::create_dir(); + assert!(temp.as_path().to_str().is_some()); +} diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 090280cae..323da3e09 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -22,6 +22,9 @@ clippy = { version = "0.0.42", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" +[dev-dependencies] +ethcore-devtools = { path = "../devtools" } + [features] jit = ["evmjit"] evm-debug = [] diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 9240ff800..fc823411f 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -664,6 +664,7 @@ mod tests { use util::hash::*; use blockchain::*; use tests::helpers::*; + use devtools::*; #[test] fn valid_tests_extra32() { @@ -679,7 +680,7 @@ mod tests { assert_eq!(bc.best_block_hash(), genesis_hash.clone()); assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.block_hash(1), None); - + let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); bc.insert_block(&first); @@ -855,7 +856,7 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); bc.insert_block(&b1); - + let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); for t in transactions { diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 6a9f84073..a386e2854 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -20,6 +20,7 @@ use pod_state::*; use block::Block; use ethereum; use tests::helpers::*; +use devtools::*; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 8e59cf7a2..9deb3a691 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -92,6 +92,7 @@ extern crate env_logger; extern crate num_cpus; extern crate crossbeam; +#[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(feature = "jit" )] extern crate evmjit; pub mod block; diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index bbec8cd37..8bbf317c1 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -163,7 +163,7 @@ impl State { /// Mutate storage of account `address` so that it is `value` for `key`. pub fn storage_at(&self, address: &Address, key: &H256) -> H256 { - self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(&self.db, address), key)) + self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(&self.db, address), key)) } /// Mutate storage of account `a` so that it is `value` for `key`. @@ -341,6 +341,7 @@ use util::rlp::*; use util::uint::*; use account::*; use tests::helpers::*; +use devtools::*; #[test] fn code_from_database() { diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d025b4b78..af25d1b72 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -17,6 +17,7 @@ use client::{BlockChainClient, Client, BlockId}; use tests::helpers::*; use common::*; +use devtools::*; #[test] fn created() { diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 93e3e0a0d..56653e820 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -15,17 +15,15 @@ // along with Parity. If not, see . use client::{BlockChainClient, Client}; -use std::env; use common::*; -use std::path::PathBuf; use spec::*; -use std::fs::{remove_dir_all}; use blockchain::{BlockChain}; use state::*; use rocksdb::*; use evm::{Schedule, Factory}; use engine::*; use ethereum; +use devtools::*; #[cfg(feature = "json-tests")] pub enum ChainEra { @@ -33,36 +31,6 @@ pub enum ChainEra { Homestead, } -pub struct RandomTempPath { - path: PathBuf -} - -impl RandomTempPath { - pub fn new() -> RandomTempPath { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - RandomTempPath { - path: dir.clone() - } - } - - pub fn as_path(&self) -> &PathBuf { - &self.path - } - - pub fn as_str(&self) -> &str { - self.path.to_str().unwrap() - } -} - -impl Drop for RandomTempPath { - fn drop(&mut self) { - if let Err(e) = remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); - } - } -} - #[cfg(test)] pub struct GuardedTempResult { result: Option, diff --git a/util/Cargo.toml b/util/Cargo.toml index 18e9a0a75..d01b0e495 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -31,6 +31,10 @@ json-tests = { path = "json-tests" } target_info = "0.1.0" igd = "0.4.2" +[dev-dependencies] +ethcore-devtools = { path = "../devtools" } + [features] default = [] dev = ["clippy"] +test = [] diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 23c483482..bc875db3f 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -1030,7 +1030,7 @@ mod file_tests { mod directory_tests { use super::{KeyDirectory, new_uuid, uuid_to_string, KeyFileContent, KeyFileCrypto, MAX_CACHE_USAGE_TRACK}; use common::*; - use tests::helpers::*; + use devtools::*; #[test] fn key_directory_locates_keys() { @@ -1110,7 +1110,7 @@ mod directory_tests { mod specs { use super::*; use common::*; - use tests::helpers::*; + use devtools::*; #[test] fn can_initiate_key_directory() { diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index b8b0b0a47..ae44d567a 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -70,7 +70,7 @@ impl SecretStore { } #[cfg(test)] - fn new_test(path: &::tests::helpers::RandomTempPath) -> SecretStore { + fn new_test(path: &::devtools::RandomTempPath) -> SecretStore { SecretStore { directory: KeyDirectory::new(path.as_path()) } @@ -203,7 +203,7 @@ mod vector_tests { #[cfg(test)] mod tests { use super::*; - use tests::helpers::*; + use devtools::*; use common::*; #[test] diff --git a/util/src/lib.rs b/util/src/lib.rs index 59713a107..8f354b7c7 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -106,6 +106,8 @@ extern crate serde; #[macro_use] extern crate log as rlog; extern crate igd; +#[cfg(test)] +extern crate ethcore_devtools as devtools; pub mod standard; #[macro_use] @@ -160,5 +162,3 @@ pub use network::*; pub use io::*; pub use log::*; -#[cfg(test)] -mod tests; diff --git a/util/src/tests/helpers.rs b/util/src/tests/helpers.rs deleted file mode 100644 index fee3d2cbb..000000000 --- a/util/src/tests/helpers.rs +++ /dev/null @@ -1,31 +0,0 @@ -use common::*; -use std::path::PathBuf; -use std::fs::{remove_dir_all}; -use std::env; - -pub struct RandomTempPath { - path: PathBuf -} - -impl RandomTempPath { - pub fn create_dir() -> RandomTempPath { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - fs::create_dir_all(dir.as_path()).unwrap(); - RandomTempPath { - path: dir.clone() - } - } - - pub fn as_path(&self) -> &PathBuf { - &self.path - } -} - -impl Drop for RandomTempPath { - fn drop(&mut self) { - if let Err(e) = remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); - } - } -} diff --git a/util/src/tests/mod.rs b/util/src/tests/mod.rs deleted file mode 100644 index 1630fabcd..000000000 --- a/util/src/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod helpers; From bd18b4930d18af803d7afd6c61437975f3258fbf Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 19 Feb 2016 17:20:02 +0300 Subject: [PATCH 126/753] license for random_path.rs --- devtools/src/random_path.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/devtools/src/random_path.rs b/devtools/src/random_path.rs index 3cbd19b96..b037867fa 100644 --- a/devtools/src/random_path.rs +++ b/devtools/src/random_path.rs @@ -1,3 +1,21 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Random path + use std::path::*; use std::fs; use std::env; From 3253d2a17b5f6e4fda28a043f74cb1d40c1adbd8 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 19 Feb 2016 15:34:12 +0100 Subject: [PATCH 127/753] fixed ethsync tests compile errors and warnings --- sync/src/range_collection.rs | 2 +- sync/src/tests/helpers.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index c3333ab63..dc2f4e446 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -207,7 +207,7 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } #[test] -#[allow(cyclomatic_complexity)] +#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_range() { use std::cmp::{Ordering}; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index ca6d79814..7f2928ccd 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -23,6 +23,8 @@ use io::SyncIo; use chain::{ChainSync}; use ethcore::receipt::Receipt; use ethcore::transaction::LocalizedTransaction; +use ethcore::filter::Filter; +use ethcore::log_entry::LocalizedLogEntry; pub struct TestBlockChainClient { pub blocks: RwLock>, @@ -115,6 +117,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn logs(&self, filter: Filter) -> Vec { + unimplemented!(); + } + fn block_header(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) } From ab0fe65f3f1cc6387c63947da8236f76325330b4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 19 Feb 2016 18:09:31 +0300 Subject: [PATCH 128/753] unlisting as dev-dependencies --- Cargo.lock | 9 +++++++++ Cargo.toml | 1 + ethcore/Cargo.toml | 2 -- util/Cargo.toml | 4 ---- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b69736c2e..6ae4a06ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ dependencies = [ "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", + "ethcore-devtools 0.9.99", "ethcore-rpc 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", @@ -184,6 +185,13 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-devtools" +version = "0.9.99" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-rpc" version = "0.9.99" @@ -212,6 +220,7 @@ dependencies = [ "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", + "ethcore-devtools 0.9.99", "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 5b59b26f1..3cb158df7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" daemonize = "0.2" +ethcore-devtools = { path = "devtools" } [features] default = ["rpc"] diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 323da3e09..d34a5478b 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -21,8 +21,6 @@ num_cpus = "0.2" clippy = { version = "0.0.42", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" - -[dev-dependencies] ethcore-devtools = { path = "../devtools" } [features] diff --git a/util/Cargo.toml b/util/Cargo.toml index d01b0e495..0ff7fe318 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -30,11 +30,7 @@ clippy = { version = "0.0.42", optional = true } json-tests = { path = "json-tests" } target_info = "0.1.0" igd = "0.4.2" - -[dev-dependencies] ethcore-devtools = { path = "../devtools" } - [features] default = [] dev = ["clippy"] -test = [] From 9648081abe1492629e0b2c15d7edb7e5c0c790c2 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 16:14:17 +0100 Subject: [PATCH 129/753] exclude common headers from coverage --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ab9a08b9..a6dadbf04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,11 +44,11 @@ after_success: | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && cargo test --no-run ${KCOV_FEATURES} ${TARGETS} && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && From ab233a941f83fd4f162de2c6a8a10ca5fc917ddd Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 16:34:31 +0100 Subject: [PATCH 130/753] Slightly improved tests --- util/src/network/host.rs | 7 +++++++ util/src/network/node_table.rs | 1 + util/src/network/tests.rs | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index b2be68a32..78fb274fa 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -209,6 +209,12 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone } } + /// Send an IO message + pub fn message(&self, msg: Message) { + self.io.message(NetworkIoMessage::User(msg)); + } + + /// Disable current protocol capability for given peer. If no capabilities left peer gets disconnected. pub fn disable_peer(&self, peer: PeerId) { //TODO: remove capability, disconnect if no capabilities left @@ -754,6 +760,7 @@ impl IoHandler> for Host where Messa io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); } + self.maintain_network(io) } fn stream_hup(&self, io: &IoContext>, stream: StreamToken) { diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index f528f7134..7ca060f75 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -332,6 +332,7 @@ impl Drop for NodeTable { } } +/// Check if node url is valid pub fn is_valid_node_url(url: &str) -> bool { use std::str::FromStr; Node::from_str(url).is_ok() diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index dc80936d2..44d53bdbe 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -74,6 +74,7 @@ impl NetworkProtocolHandler for TestProtocol { } fn connected(&self, io: &NetworkContext, peer: &PeerId) { + assert!(io.peer_info(*peer).contains("parity")); if self.drop_session { io.disconnect_peer(*peer) } else { @@ -86,7 +87,8 @@ impl NetworkProtocolHandler for TestProtocol { } /// Timer function called after a timeout created with `NetworkContext::timeout`. - fn timeout(&self, _io: &NetworkContext, timer: TimerToken) { + fn timeout(&self, io: &NetworkContext, timer: TimerToken) { + io.message(TestProtocolMessage { payload: 22 }); assert_eq!(timer, 0); self.got_timeout.store(true, AtomicOrdering::Relaxed); } From 2a1d984bf1053e97f24e5af5fa04d83b6dc54f59 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 16:41:05 +0100 Subject: [PATCH 131/753] exclude common headers from coverage --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6dadbf04..ddddca3b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,11 +44,11 @@ after_success: | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && cargo test --no-run ${KCOV_FEATURES} ${TARGETS} && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && From 5572d1792d3546df050785e34ebfe3f8712d0961 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 18:42:54 +0100 Subject: [PATCH 132/753] Back to original slab crate --- Cargo.lock | 7 +------ util/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 250acb5a8..d4d1ceaff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,7 +226,7 @@ dependencies = [ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", - "slab 0.1.4 (git+https://github.com/arkpar/slab.git)", + "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -643,11 +643,6 @@ name = "slab" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "slab" -version = "0.1.4" -source = "git+https://github.com/arkpar/slab.git#3c9284e1f010e394c9d0359b27464e8fb5c87bf0" - [[package]] name = "solicit" version = "0.4.4" diff --git a/util/Cargo.toml b/util/Cargo.toml index 2675ba56c..c27d4bdc3 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -23,7 +23,7 @@ elastic-array = "0.4" heapsize = "0.3" itertools = "0.4" crossbeam = "0.2" -slab = { git = "https://github.com/arkpar/slab.git" } +slab = "0.1" sha3 = { path = "sha3" } serde = "0.6.7" clippy = { version = "0.0.42", optional = true } From 6c82e405ddae5de03b784d2608c66a9dc4f8b683 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 19:42:23 +0100 Subject: [PATCH 133/753] Remove regex &c., use network code for enode ID. --- Cargo.lock | 1 - Cargo.toml | 2 -- parity/main.rs | 12 +++--------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34b618c2b..8891e4658 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,6 @@ dependencies = [ "ethcore-util 0.9.99", "ethsync 0.9.99", "fdlimit 0.1.0", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index f4163253b..5b59b26f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,6 @@ ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" daemonize = "0.2" -regex = "0.1" -lazy_static = "0.1" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index aca2b9c03..0f1f77606 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -26,8 +26,6 @@ extern crate ethcore; extern crate ethsync; #[macro_use] extern crate log as rlog; -#[macro_use] -extern crate lazy_static; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; @@ -40,11 +38,13 @@ extern crate ethcore_rpc as rpc; use std::net::{SocketAddr}; use std::env; +use std::from_str::FromStr; use std::process::exit; use rlog::{LogLevelFilter}; use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; +use util::network::node::Node; use util::panics::MayPanic; use ethcore::spec::*; use ethcore::client::*; @@ -194,13 +194,7 @@ impl Configuration { } fn normalize_enode(e: &str) -> Option { - lazy_static! { - static ref RE: Regex = Regex::new(r"^enode://([0-9a-fA-F]{64})@(\d+\.\d+\.\d+\.\d+):(\d+)$").unwrap(); - } - match RE.is_match(e) { - true => Some(e.to_owned()), - false => None, - } + Node::from_str(e).ok().map(|_| e.to_owned()) } fn init_nodes(&self, spec: &Spec) -> Vec { From dc3ceeb5bb89d731d9ad2b0bf2431d76cabd84c0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Feb 2016 20:02:23 +0100 Subject: [PATCH 134/753] Use new is_valid_node_url function. --- Cargo.lock | 1 - parity/main.rs | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d475f81e1..250acb5a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,6 @@ dependencies = [ "ethsync 0.9.99", "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/parity/main.rs b/parity/main.rs index 8930c60e9..58d3a6f4c 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -31,21 +31,18 @@ extern crate ctrlc; extern crate fdlimit; extern crate target_info; extern crate daemonize; -extern crate regex; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; use std::net::{SocketAddr}; use std::env; -use std::from_str::FromStr; use std::process::exit; use std::path::PathBuf; use rlog::{LogLevelFilter}; use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; -use util::network::node::Node; use util::panics::MayPanic; use ethcore::spec::*; use ethcore::client::*; @@ -56,7 +53,6 @@ use ethsync::EthSync; use docopt::Docopt; use target_info::Target; use daemonize::Daemonize; -use regex::Regex; const USAGE: &'static str = " Parity. Ethereum Client. @@ -199,7 +195,10 @@ impl Configuration { } fn normalize_enode(e: &str) -> Option { - Node::from_str(e).ok().map(|_| e.to_owned()) + match is_valid_node_url(e) { + true => Some(e.to_owned()), + false => None, + } } fn init_nodes(&self, spec: &Spec) -> Vec { @@ -244,6 +243,7 @@ impl Configuration { let mut net_path = PathBuf::from(&self.path()); net_path.push("network"); ret.config_path = Some(net_path.to_str().unwrap().to_owned()); + ret } fn execute(&self) { From e64d3daa068e50afa6b3902965c7ebf54256d131 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 20:14:28 +0100 Subject: [PATCH 135/753] exclude common headers from coverage --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index ddddca3b8..c4776679e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,12 +44,12 @@ after_success: | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && cargo test --no-run ${KCOV_FEATURES} ${TARGETS} && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern usr/include,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && - ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.cargo,/root/.multirust target/kcov target/debug/parity-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && + ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && [ $TRAVIS_RUST_VERSION = beta ] && From 69df91de68fe1e345b0fd5e4202079e21bb7f3ae Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 19 Feb 2016 22:09:06 +0100 Subject: [PATCH 136/753] Deregister handshake properly when converting to session --- util/src/network/connection.rs | 29 ++++++++++++++++++++++++----- util/src/network/host.rs | 29 +++++++++++++---------------- util/src/network/session.rs | 10 ++++++++-- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 9e9304ca6..4b7886698 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -175,6 +175,18 @@ impl Connection { self.socket.peer_addr() } + pub fn try_clone(&self) -> io::Result { + Ok(Connection { + token: self.token, + socket: try!(self.socket.try_clone()), + rec_buf: Vec::new(), + rec_size: 0, + send_queue: VecDeque::new(), + interest: EventSet::hup() | EventSet::readable(), + stats: self.stats.clone(), + }) + } + /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "net", "connection register; token={:?}", reg); @@ -265,7 +277,7 @@ impl EncryptedConnection { } /// Create an encrypted connection out of the handshake. Consumes a handshake object. - pub fn new(mut handshake: Handshake) -> Result { + pub fn new(handshake: &mut Handshake) -> Result { let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public)); let mut nonce_material = H512::new(); if handshake.originated { @@ -300,9 +312,8 @@ impl EncryptedConnection { ingress_mac.update(&mac_material); ingress_mac.update(if handshake.originated { &handshake.ack_cipher } else { &handshake.auth_cipher }); - handshake.connection.expect(ENCRYPTED_HEADER_LEN); - Ok(EncryptedConnection { - connection: handshake.connection, + let mut enc = EncryptedConnection { + connection: try!(handshake.connection.try_clone()), encoder: encoder, decoder: decoder, mac_encoder: mac_encoder, @@ -311,7 +322,9 @@ impl EncryptedConnection { read_state: EncryptedConnectionState::Header, protocol_id: 0, payload_len: 0 - }) + }; + enc.connection.expect(ENCRYPTED_HEADER_LEN); + Ok(enc) } /// Send a packet @@ -440,6 +453,12 @@ impl EncryptedConnection { Ok(()) } + /// Register socket with the event lpop. This should be called at the end of the event loop. + pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + try!(self.connection.register_socket(reg, event_loop)); + Ok(()) + } + /// Update connection registration. This should be called at the end of the event loop. pub fn update_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { try!(self.connection.update_socket(reg, event_loop)); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 78fb274fa..f4f3b4e1b 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -544,7 +544,7 @@ impl Host where Message: Send + Sync + Clone { if let Some(handshake) = handshake { let mut h = handshake.lock().unwrap(); if let Err(e) = h.writable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake write error: {}:{:?}", token, e); + trace!(target: "net", "Handshake write error: {}: {:?}", token, e); } } } @@ -554,7 +554,7 @@ impl Host where Message: Send + Sync + Clone { if let Some(session) = session { let mut s = session.lock().unwrap(); if let Err(e) = s.writable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Session write error: {}:{:?}", token, e); + trace!(target: "net", "Session write error: {}: {:?}", token, e); } io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); } @@ -571,7 +571,7 @@ impl Host where Message: Send + Sync + Clone { if let Some(handshake) = handshake { let mut h = handshake.lock().unwrap(); if let Err(e) = h.readable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake read error: {}:{:?}", token, e); + debug!(target: "net", "Handshake read error: {}: {:?}", token, e); kill = true; } if h.done() { @@ -583,7 +583,7 @@ impl Host where Message: Send + Sync + Clone { return; } else if create_session { self.start_session(token, io); - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); + return; } io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); } @@ -597,7 +597,7 @@ impl Host where Message: Send + Sync + Clone { let mut s = session.lock().unwrap(); match s.readable(io, &self.info.read().unwrap()) { Err(e) => { - debug!(target: "net", "Session read error: {}:{:?}", token, e); + debug!(target: "net", "Session read error: {}: {:?}", token, e); kill = true; }, Ok(SessionData::Ready) => { @@ -642,16 +642,9 @@ impl Host where Message: Send + Sync + Clone { // turn a handshake into a session let mut sessions = self.sessions.write().unwrap(); - let mut h = handshakes.remove(token).unwrap(); - // wait for other threads to stop using it - { - while Arc::get_mut(&mut h).is_none() { - h.lock().ok(); - } - } - let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap(); + let mut h = handshakes.get_mut(token).unwrap().lock().unwrap(); let originated = h.originated; - let mut session = match Session::new(h, &self.info.read().unwrap()) { + let mut session = match Session::new(&mut h, &self.info.read().unwrap()) { Ok(s) => s, Err(e) => { debug!("Session creation error: {:?}", e); @@ -660,7 +653,8 @@ impl Host where Message: Send + Sync + Clone { }; let result = sessions.insert_with(move |session_token| { session.set_token(session_token); - io.update_registration(session_token).expect("Error updating session registration"); + io.deregister_stream(token).expect("Error deleting handshake registration"); + io.register_stream(session_token).expect("Error creating session registration"); self.stats.inc_sessions(); if !originated { // Add it no node table @@ -872,7 +866,10 @@ impl IoHandler> for Host where Messa fn register_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { FIRST_SESSION ... LAST_SESSION => { - warn!("Unexpected session stream registration"); + let session = { self.sessions.read().unwrap().get(stream).cloned() }; + if let Some(session) = session { + session.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); + } } FIRST_HANDSHAKE ... LAST_HANDSHAKE => { let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; diff --git a/util/src/network/session.rs b/util/src/network/session.rs index b0db5f7ef..159dc795d 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -109,8 +109,8 @@ const PACKET_USER: u8 = 0x10; const PACKET_LAST: u8 = 0x7f; impl Session { - /// Create a new session out of comepleted handshake. Consumes handshake object. - pub fn new(h: Handshake, host: &HostInfo) -> Result { + /// Create a new session out of comepleted handshake. + pub fn new(h: &mut Handshake, host: &HostInfo) -> Result { let id = h.id.clone(); let connection = try!(EncryptedConnection::new(h)); let mut session = Session { @@ -169,6 +169,12 @@ impl Session { self.info.capabilities.iter().any(|c| c.protocol == protocol) } + /// Register the session socket with the event loop + pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + try!(self.connection.register_socket(reg, event_loop)); + Ok(()) + } + /// Update registration with the event loop. Should be called at the end of the IO handler. pub fn update_socket(&self, reg:Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { self.connection.update_socket(reg, event_loop) From 0b48507d399423efbfa7732e95bc03122f9e4cc3 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 20 Feb 2016 12:38:16 +0300 Subject: [PATCH 137/753] Delete LICENSE.txt --- devtools/LICENSE.txt | 675 ------------------------------------------- 1 file changed, 675 deletions(-) delete mode 100644 devtools/LICENSE.txt diff --git a/devtools/LICENSE.txt b/devtools/LICENSE.txt deleted file mode 100644 index 733c07236..000000000 --- a/devtools/LICENSE.txt +++ /dev/null @@ -1,675 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program 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. - - This program 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 this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. - From b1bfd00875be0230763ce3a98c89e789e01dc2c0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 20 Feb 2016 01:10:27 +0100 Subject: [PATCH 138/753] Zombie connections --- ethcore/res/ethereum/tests | 2 +- util/src/network/connection.rs | 8 ++-- util/src/network/handshake.rs | 73 ++++++++++++++++++++++------------ util/src/network/host.rs | 71 +++++++++++++++++++-------------- util/src/network/session.rs | 25 ++++++++++++ util/src/network/tests.rs | 2 +- 6 files changed, 120 insertions(+), 61 deletions(-) diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index 3116f85a4..f32954b3d 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 3116f85a499ceaf4dfdc46726060fc056e2d7829 +Subproject commit f32954b3ddb5af2dc3dc9ec6d9a28bee848fdf70 diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 4b7886698..0135fc333 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -181,7 +181,7 @@ impl Connection { socket: try!(self.socket.try_clone()), rec_buf: Vec::new(), rec_size: 0, - send_queue: VecDeque::new(), + send_queue: self.send_queue.clone(), interest: EventSet::hup() | EventSet::readable(), stats: self.stats.clone(), }) @@ -190,10 +190,10 @@ impl Connection { /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "net", "connection register; token={:?}", reg); - event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| { + if let Err(e) = event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()) { debug!("Failed to register {:?}, {:?}", reg, e); - Ok(()) - }) + } + Ok(()) } /// Update connection registration. Should be called at the end of the IO handler. diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 5d43decd7..a50dd6ba2 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -63,7 +63,9 @@ pub struct Handshake { /// A copy of received encryped auth packet pub auth_cipher: Bytes, /// A copy of received encryped ack packet - pub ack_cipher: Bytes + pub ack_cipher: Bytes, + /// This Handshake is marked for deleteion flag + pub expired: bool, } const AUTH_PACKET_SIZE: usize = 307; @@ -84,6 +86,7 @@ impl Handshake { remote_nonce: H256::new(), auth_cipher: Bytes::new(), ack_cipher: Bytes::new(), + expired: false, }) } @@ -97,6 +100,16 @@ impl Handshake { self.connection.token() } + /// Mark this handshake as inactive to be deleted lated. + pub fn set_expired(&mut self) { + self.expired = true; + } + + /// Check if this handshake is expired. + pub fn expired(&self) -> bool { + self.expired + } + /// Start a handhsake pub fn start(&mut self, io: &IoContext, host: &HostInfo, originated: bool) -> Result<(), UtilError> where Message: Send + Clone{ self.originated = originated; @@ -118,47 +131,55 @@ impl Handshake { /// Readable IO handler. Drives the state change. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { - io.clear_timer(self.connection.token).unwrap(); - match self.state { - HandshakeState::ReadingAuth => { - if let Some(data) = try!(self.connection.readable()) { - try!(self.read_auth(host, &data)); - try!(self.write_ack()); - }; - }, - HandshakeState::ReadingAck => { - if let Some(data) = try!(self.connection.readable()) { - try!(self.read_ack(host, &data)); - self.state = HandshakeState::StartSession; - }; - }, - HandshakeState::StartSession => {}, - _ => { panic!("Unexpected state"); } - } - if self.state != HandshakeState::StartSession { - try!(io.update_registration(self.connection.token)); + if !self.expired() { + io.clear_timer(self.connection.token).unwrap(); + match self.state { + HandshakeState::ReadingAuth => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_auth(host, &data)); + try!(self.write_ack()); + }; + }, + HandshakeState::ReadingAck => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_ack(host, &data)); + self.state = HandshakeState::StartSession; + }; + }, + HandshakeState::StartSession => {}, + _ => { panic!("Unexpected state"); } + } + if self.state != HandshakeState::StartSession { + try!(io.update_registration(self.connection.token)); + } } Ok(()) } /// Writabe IO handler. pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { - io.clear_timer(self.connection.token).unwrap(); - try!(self.connection.writable()); - if self.state != HandshakeState::StartSession { - io.update_registration(self.connection.token).unwrap(); + if !self.expired() { + io.clear_timer(self.connection.token).unwrap(); + try!(self.connection.writable()); + if self.state != HandshakeState::StartSession { + io.update_registration(self.connection.token).unwrap(); + } } Ok(()) } /// Register the socket with the event loop pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.register_socket(reg, event_loop)); + if !self.expired() { + try!(self.connection.register_socket(reg, event_loop)); + } Ok(()) } pub fn update_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.update_socket(reg, event_loop)); + if !self.expired() { + try!(self.connection.update_socket(reg, event_loop)); + } Ok(()) } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index f4f3b4e1b..95b778531 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -190,11 +190,11 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone let session = { self.sessions.read().unwrap().get(peer).cloned() }; if let Some(session) = session { session.lock().unwrap().deref_mut().send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| { - warn!(target: "net", "Send error: {:?}", e); + warn!(target: "network", "Send error: {:?}", e); }); //TODO: don't copy vector data try!(self.io.update_registration(peer)); } else { - trace!(target: "net", "Send: Peer no longer exist") + trace!(target: "network", "Send: Peer no longer exist") } Ok(()) } @@ -470,18 +470,18 @@ impl Host where Message: Send + Sync + Clone { .take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) { self.connect_peer(&id, io); } - debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); + debug!(target: "network", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); } #[cfg_attr(feature="dev", allow(single_match))] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { - trace!("Aborted connect. Node already connected."); + trace!(target: "network", "Aborted connect. Node already connected."); return; } if self.connecting_to(id) { - trace!("Aborted connect. Node already connecting."); + trace!(target: "network", "Aborted connect. Node already connecting."); return; } @@ -493,7 +493,7 @@ impl Host where Message: Send + Sync + Clone { node.endpoint.address } else { - debug!("Connection to expired node aborted"); + debug!(target: "network", "Connection to expired node aborted"); return; } }; @@ -515,16 +515,16 @@ impl Host where Message: Send + Sync + Clone { if handshakes.insert_with(|token| { let mut handshake = Handshake::new(token, id, socket, &nonce, self.stats.clone()).expect("Can't create handshake"); handshake.start(io, &self.info.read().unwrap(), id.is_some()).and_then(|_| io.register_stream(token)).unwrap_or_else (|e| { - debug!(target: "net", "Handshake create error: {:?}", e); + debug!(target: "network", "Handshake create error: {:?}", e); }); Arc::new(Mutex::new(handshake)) }).is_none() { - debug!("Max handshakes reached"); + debug!(target: "network", "Max handshakes reached"); } } fn accept(&self, io: &IoContext>) { - trace!(target: "net", "accept"); + trace!(target: "network", "Accepting incoming connection"); loop { let socket = match self.tcp_listener.lock().unwrap().accept() { Ok(None) => break, @@ -544,7 +544,7 @@ impl Host where Message: Send + Sync + Clone { if let Some(handshake) = handshake { let mut h = handshake.lock().unwrap(); if let Err(e) = h.writable(io, &self.info.read().unwrap()) { - trace!(target: "net", "Handshake write error: {}: {:?}", token, e); + trace!(target: "network", "Handshake write error: {}: {:?}", token, e); } } } @@ -554,9 +554,9 @@ impl Host where Message: Send + Sync + Clone { if let Some(session) = session { let mut s = session.lock().unwrap(); if let Err(e) = s.writable(io, &self.info.read().unwrap()) { - trace!(target: "net", "Session write error: {}: {:?}", token, e); + trace!(target: "network", "Session write error: {}: {:?}", token, e); } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Session registration error: {:?}", e)); } } @@ -571,7 +571,7 @@ impl Host where Message: Send + Sync + Clone { if let Some(handshake) = handshake { let mut h = handshake.lock().unwrap(); if let Err(e) = h.readable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake read error: {}: {:?}", token, e); + debug!(target: "network", "Handshake read error: {}: {:?}", token, e); kill = true; } if h.done() { @@ -585,7 +585,7 @@ impl Host where Message: Send + Sync + Clone { self.start_session(token, io); return; } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); } fn session_readable(&self, token: StreamToken, io: &IoContext>) { @@ -597,7 +597,7 @@ impl Host where Message: Send + Sync + Clone { let mut s = session.lock().unwrap(); match s.readable(io, &self.info.read().unwrap()) { Err(e) => { - debug!(target: "net", "Session read error: {}: {:?}", token, e); + debug!(target: "network", "Session read error: {}: {:?}", token, e); kill = true; }, Ok(SessionData::Ready) => { @@ -613,7 +613,7 @@ impl Host where Message: Send + Sync + Clone { packet_id, }) => { match self.handlers.read().unwrap().get(protocol) { - None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) }, + None => { warn!(target: "network", "No handler found for protocol: {:?}", protocol) }, Some(_) => packet_data = Some((protocol, packet_id, data)), } }, @@ -631,7 +631,7 @@ impl Host where Message: Send + Sync + Clone { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); h.read(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token, packet_id, &data[1..]); } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); } fn start_session(&self, token: StreamToken, io: &IoContext>) { @@ -643,19 +643,24 @@ impl Host where Message: Send + Sync + Clone { // turn a handshake into a session let mut sessions = self.sessions.write().unwrap(); let mut h = handshakes.get_mut(token).unwrap().lock().unwrap(); + if h.expired { + return; + } let originated = h.originated; let mut session = match Session::new(&mut h, &self.info.read().unwrap()) { Ok(s) => s, Err(e) => { - debug!("Session creation error: {:?}", e); + debug!(target: "network", "Session creation error: {:?}", e); return; } }; let result = sessions.insert_with(move |session_token| { session.set_token(session_token); io.deregister_stream(token).expect("Error deleting handshake registration"); + h.set_expired(); io.register_stream(session_token).expect("Error creating session registration"); self.stats.inc_sessions(); + trace!(target: "network", "Creating session {} -> {}", token, session_token); if !originated { // Add it no node table if let Ok(address) = session.remote_addr() { @@ -684,26 +689,34 @@ impl Host where Message: Send + Sync + Clone { FIRST_HANDSHAKE ... LAST_HANDSHAKE => { let handshakes = self.handshakes.write().unwrap(); if let Some(handshake) = handshakes.get(token).cloned() { - failure_id = Some(handshake.lock().unwrap().id().clone()); + let mut handshake = handshake.lock().unwrap(); + if !handshake.expired() { + handshake.set_expired(); + failure_id = Some(handshake.id().clone()); + io.deregister_stream(token).expect("Error deregistering stream"); + } } }, FIRST_SESSION ... LAST_SESSION => { let sessions = self.sessions.write().unwrap(); if let Some(session) = sessions.get(token).cloned() { - let s = session.lock().unwrap(); - if s.is_ready() { - for (p, _) in self.handlers.read().unwrap().iter() { - if s.have_capability(p) { - to_disconnect.push(p); + let mut s = session.lock().unwrap(); + if !s.expired() { + if s.is_ready() { + for (p, _) in self.handlers.read().unwrap().iter() { + if s.have_capability(p) { + to_disconnect.push(p); + } } } + s.set_expired(); + failure_id = Some(s.id().clone()); + io.deregister_stream(token).expect("Error deregistering stream"); } - failure_id = Some(s.id().clone()); } }, _ => {}, } - io.deregister_stream(token).expect("Error deregistering stream"); if let Some(id) = failure_id { if remote { self.nodes.write().unwrap().note_failure(&id); @@ -758,11 +771,11 @@ impl IoHandler> for Host where Messa } fn stream_hup(&self, io: &IoContext>, stream: StreamToken) { - trace!(target: "net", "Hup: {}", stream); + trace!(target: "network", "Hup: {}", stream); match stream { FIRST_SESSION ... LAST_SESSION => self.connection_closed(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_closed(stream, io), - _ => warn!(target: "net", "Unexpected hup"), + _ => warn!(target: "network", "Unexpected hup"), }; } @@ -810,7 +823,7 @@ impl IoHandler> for Host where Messa }, _ => match self.timers.read().unwrap().get(&token).cloned() { Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() { - None => { warn!(target: "net", "No handler found for protocol: {:?}", timer.protocol) }, + None => { warn!(target: "network", "No handler found for protocol: {:?}", timer.protocol) }, Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.sessions.clone()), timer.token); } }, None => { warn!("Unknown timer token: {}", token); } // timer is not registerd through us diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 159dc795d..6be1dbfe4 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -41,6 +41,8 @@ pub struct Session { connection: EncryptedConnection, /// Session ready flag. Set after successfull Hello packet exchange had_hello: bool, + /// Session is no longer active flag. + expired: bool, ping_time_ns: u64, pong_time_ns: Option, } @@ -125,6 +127,7 @@ impl Session { }, ping_time_ns: 0, pong_time_ns: None, + expired: false, }; try!(session.write_hello(host)); try!(session.send_ping()); @@ -141,6 +144,16 @@ impl Session { self.had_hello } + /// Mark this session as inactive to be deleted lated. + pub fn set_expired(&mut self) { + self.expired = true; + } + + /// Check if this session is expired. + pub fn expired(&self) -> bool { + self.expired + } + /// Replace socket token pub fn set_token(&mut self, token: StreamToken) { self.connection.set_token(token); @@ -153,6 +166,9 @@ impl Session { /// Readable IO handler. Returns packet data if available. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result where Message: Send + Sync + Clone { + if self.expired() { + return Ok(SessionData::None) + } match try!(self.connection.readable(io)) { Some(data) => Ok(try!(self.read_packet(data, host))), None => Ok(SessionData::None) @@ -161,6 +177,9 @@ impl Session { /// Writable IO handler. Sends pending packets. pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Sync + Clone { + if self.expired() { + return Ok(()) + } self.connection.writable(io) } @@ -171,12 +190,18 @@ impl Session { /// Register the session socket with the event loop pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + if self.expired() { + return Ok(()); + } try!(self.connection.register_socket(reg, event_loop)); Ok(()) } /// Update registration with the event loop. Should be called at the end of the IO handler. pub fn update_socket(&self, reg:Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + if self.expired() { + return Ok(()); + } self.connection.update_socket(reg, event_loop) } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index 44d53bdbe..f8ef588f6 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -74,7 +74,7 @@ impl NetworkProtocolHandler for TestProtocol { } fn connected(&self, io: &NetworkContext, peer: &PeerId) { - assert!(io.peer_info(*peer).contains("parity")); + assert!(io.peer_info(*peer).contains("Parity")); if self.drop_session { io.disconnect_peer(*peer) } else { From 8bd052b9869de1853c1251a28887d2213211a5b2 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 20 Feb 2016 11:54:12 +0100 Subject: [PATCH 139/753] Fixed warnings --- ethcore/res/ethereum/tests | 2 +- ethcore/src/blockchain.rs | 2 +- ethcore/src/evm/tests.rs | 2 +- util/src/hash.rs | 2 +- util/src/panics.rs | 10 +--------- util/src/uint.rs | 2 +- 6 files changed, 6 insertions(+), 14 deletions(-) diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index 3116f85a4..f32954b3d 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 3116f85a499ceaf4dfdc46726060fc056e2d7829 +Subproject commit f32954b3ddb5af2dc3dc9ec6d9a28bee848fdf70 diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 9240ff800..2e9a867c4 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -696,7 +696,7 @@ mod tests { } #[test] - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 02f929192..9d4dd3bc4 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -25,7 +25,7 @@ struct FakeLogEntry { } #[derive(PartialEq, Eq, Hash, Debug)] -#[allow(enum_variant_names)] // Common prefix is C ;) +#[cfg_attr(feature="dev", allow(enum_variant_names))] // Common prefix is C ;) enum FakeCallType { CALL, CREATE } diff --git a/util/src/hash.rs b/util/src/hash.rs index d436c2d81..71c690ef6 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -635,7 +635,7 @@ mod tests { use std::str::FromStr; #[test] - #[allow(eq_op)] + #[cfg_attr(feature="dev", allow(eq_op))] fn hash() { let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); diff --git a/util/src/panics.rs b/util/src/panics.rs index 18ed9ecb1..60d85ef14 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -18,7 +18,6 @@ use std::thread; use std::ops::DerefMut; -use std::any::Any; use std::sync::{Arc, Mutex}; /// Thread-safe closure for handling possible panics @@ -75,7 +74,7 @@ impl PanicHandler { #[cfg_attr(feature="dev", allow(deprecated))] // TODO [todr] catch_panic is deprecated but panic::recover has different bounds (not allowing mutex) pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { - let guard = PanicGuard { handler: self }; + let _guard = PanicGuard { handler: self }; let result = g(); Ok(result) } @@ -108,13 +107,6 @@ impl OnPanicListener for F } } -fn convert_to_string(t: &Box) -> Option { - let as_str = t.downcast_ref::<&'static str>().cloned().map(|t| t.to_owned()); - let as_string = t.downcast_ref::().cloned(); - - as_str.or(as_string) -} - #[test] #[ignore] // panic forwarding doesnt work on the same thread in beta fn should_notify_listeners_about_panic () { diff --git a/util/src/uint.rs b/util/src/uint.rs index 912088fb9..7206a521e 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -991,7 +991,7 @@ mod tests { } #[test] - #[allow(eq_op)] + #[cfg_attr(feature="dev", allow(eq_op))] pub fn uint256_comp_test() { let small = U256([10u64, 0, 0, 0]); let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); From 7bc2853de96b672a64b5f56e405ded1c8e375830 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 20 Feb 2016 15:14:54 +0100 Subject: [PATCH 140/753] Removed TODO --- util/src/panics.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/util/src/panics.rs b/util/src/panics.rs index 60d85ef14..05d266b8b 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -72,7 +72,6 @@ impl PanicHandler { /// Invoke closure and catch any possible panics. /// In case of panic notifies all listeners about it. #[cfg_attr(feature="dev", allow(deprecated))] - // TODO [todr] catch_panic is deprecated but panic::recover has different bounds (not allowing mutex) pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { let _guard = PanicGuard { handler: self }; let result = g(); From ce81a24bfdac260ee3fba477ea81f12b1240b185 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 18 Feb 2016 00:47:47 +0000 Subject: [PATCH 141/753] Tests for issue #161 Implementations of get_cache_size and get_data_size in Rust (issue #161) Removed sizes module, containing replaced data tables Fixed whitespace issues after code review --- Cargo.lock | 47 +++ ethash/Cargo.toml | 1 + ethash/src/compute.rs | 65 +++- ethash/src/lib.rs | 6 +- ethash/src/sizes.rs | 788 ------------------------------------------ 5 files changed, 102 insertions(+), 805 deletions(-) delete mode 100644 ethash/src/sizes.rs diff --git a/Cargo.lock b/Cargo.lock index d4d1ceaff..d227d4097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,6 +162,7 @@ name = "ethash" version = "0.9.99" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", ] @@ -262,6 +263,11 @@ name = "glob" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hamming" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "heapsize" version = "0.3.2" @@ -514,6 +520,47 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "primal" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "primal-check 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-estimate 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-sieve 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "primal-bit" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "primal-check" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "primal-estimate" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "primal-sieve" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-bit 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-estimate 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quasi" version = "0.7.0" diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index da08b9f92..e2a2ec4d8 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -8,3 +8,4 @@ authors = ["arkpar Self { + fn default() -> Self { Node { bytes: [0u8; NODE_BYTES] } } } @@ -109,7 +113,7 @@ impl Light { pub fn from_file(block_number: u64) -> io::Result { let path = Light::file_path(block_number); let mut file = try!(File::open(path)); - + let cache_size = get_cache_size(block_number); if try!(file.metadata()).len() != cache_size as u64 { return Err(io::Error::new(io::ErrorKind::Other, "Cache file size mismatch")); @@ -129,10 +133,10 @@ impl Light { let path = Light::file_path(self.block_number); try!(fs::create_dir_all(path.parent().unwrap())); let mut file = try!(File::create(path)); - + let cache_size = self.cache.len() * NODE_BYTES; let buf = unsafe { slice::from_raw_parts(self.cache.as_ptr() as *const u8, cache_size) }; - try!(file.write(buf)); + try!(file.write(buf)); Ok(()) } } @@ -149,14 +153,22 @@ fn sha3_512(input: &[u8], output: &mut [u8]) { #[inline] fn get_cache_size(block_number: u64) -> usize { - assert!(block_number / ETHASH_EPOCH_LENGTH < 2048); - return CACHE_SIZES[(block_number / ETHASH_EPOCH_LENGTH) as usize] as usize; + let mut sz: u64 = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH); + sz = sz - NODE_BYTES as u64; + while !is_prime(sz / NODE_BYTES as u64) { + sz = sz - 2 * NODE_BYTES as u64; + } + sz as usize } #[inline] fn get_data_size(block_number: u64) -> usize { - assert!(block_number / ETHASH_EPOCH_LENGTH < 2048); - return DAG_SIZES[(block_number / ETHASH_EPOCH_LENGTH) as usize] as usize; + let mut sz: u64 = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH); + sz = sz - ETHASH_MIX_BYTES as u64; + while !is_prime(sz / ETHASH_MIX_BYTES as u64) { + sz = sz - 2 * ETHASH_MIX_BYTES as u64; + } + sz as usize } #[inline] @@ -289,7 +301,7 @@ fn light_new(block_number: u64) -> Light { for i in 1..num_nodes { sha3::sha3_512(nodes.get_unchecked_mut(i).bytes.as_mut_ptr(), NODE_BYTES, nodes.get_unchecked(i - 1).bytes.as_ptr(), NODE_BYTES); } - + for _ in 0..ETHASH_CACHE_ROUNDS { for i in 0..num_nodes { let idx = *nodes.get_unchecked_mut(i).as_words().get_unchecked(0) as usize % num_nodes; @@ -321,10 +333,35 @@ fn to_hex(bytes: &[u8]) -> String { } } +#[test] +fn test_get_cache_size() { + // https://github.com/ethereum/wiki/wiki/Ethash/ef6b93f9596746a088ea95d01ca2778be43ae68f#data-sizes + assert_eq!(16776896usize, get_cache_size(0)); + assert_eq!(16776896usize, get_cache_size(1)); + assert_eq!(16776896usize, get_cache_size(ETHASH_EPOCH_LENGTH - 1)); + assert_eq!(16907456usize, get_cache_size(ETHASH_EPOCH_LENGTH)); + assert_eq!(16907456usize, get_cache_size(ETHASH_EPOCH_LENGTH + 1)); + assert_eq!(284950208usize, get_cache_size(2046 * ETHASH_EPOCH_LENGTH)); + assert_eq!(285081536usize, get_cache_size(2047 * ETHASH_EPOCH_LENGTH)); + assert_eq!(285081536usize, get_cache_size(2048 * ETHASH_EPOCH_LENGTH - 1)); +} + +#[test] +fn test_get_data_size() { + // https://github.com/ethereum/wiki/wiki/Ethash/ef6b93f9596746a088ea95d01ca2778be43ae68f#data-sizes + assert_eq!(1073739904usize, get_data_size(0)); + assert_eq!(1073739904usize, get_data_size(1)); + assert_eq!(1073739904usize, get_data_size(ETHASH_EPOCH_LENGTH - 1)); + assert_eq!(1082130304usize, get_data_size(ETHASH_EPOCH_LENGTH)); + assert_eq!(1082130304usize, get_data_size(ETHASH_EPOCH_LENGTH + 1)); + assert_eq!(18236833408usize, get_data_size(2046 * ETHASH_EPOCH_LENGTH)); + assert_eq!(18245220736usize, get_data_size(2047 * ETHASH_EPOCH_LENGTH)); +} + #[test] fn test_difficulty_test() { let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72]; - let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; + let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; let nonce = 0xd7b3ac70a301a249; let boundary_good = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84]; assert_eq!(quick_get_difficulty(&hash, nonce, &mix_hash)[..], boundary_good[..]); @@ -335,7 +372,7 @@ fn test_difficulty_test() { #[test] fn test_light_compute() { let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72]; - let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; + let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; let boundary = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84]; let nonce = 0xd7b3ac70a301a249; // difficulty = 0x085657254bd9u64; diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index ea7ad4868..e96b98b81 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -16,10 +16,10 @@ //! Ethash implementation //! See https://github.com/ethereum/wiki/wiki/Ethash +extern crate primal; extern crate sha3; #[macro_use] extern crate log; -mod sizes; mod compute; use std::mem; @@ -43,7 +43,7 @@ pub struct EthashManager { impl EthashManager { /// Create a new new instance of ethash manager pub fn new() -> EthashManager { - EthashManager { + EthashManager { cache: Mutex::new(LightCache { recent_epoch: None, recent: None, @@ -82,7 +82,7 @@ impl EthashManager { None => { let light = match Light::from_file(block_number) { Ok(light) => Arc::new(light), - Err(e) => { + Err(e) => { debug!("Light cache file not found for {}:{}", block_number, e); let light = Light::new(block_number); if let Err(e) = light.to_file() { diff --git a/ethash/src/sizes.rs b/ethash/src/sizes.rs deleted file mode 100644 index b3a3c0d22..000000000 --- a/ethash/src/sizes.rs +++ /dev/null @@ -1,788 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -// 2048 Epochs (~20 years) worth of tabulated DAG sizes - -// Generated with the following Mathematica Code: - -// GetCacheSizes[n_] := Module[{ -// CacheSizeBytesInit = 2^24, -// CacheGrowth = 2^17, -// HashBytes = 64, -// j = 0}, -// Reap[ -// While[j < n, -// Module[{i = -// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]}, -// While[! PrimeQ[i], i--]; -// Sow[i*HashBytes]; j++]]]][[2]][[1]] -pub const DAG_SIZES: [u64; 2048] = [ - 1073739904u64, 1082130304u64, 1090514816u64, 1098906752u64, 1107293056u64, - 1115684224u64, 1124070016u64, 1132461952u64, 1140849536u64, 1149232768u64, - 1157627776u64, 1166013824u64, 1174404736u64, 1182786944u64, 1191180416u64, - 1199568512u64, 1207958912u64, 1216345216u64, 1224732032u64, 1233124736u64, - 1241513344u64, 1249902464u64, 1258290304u64, 1266673792u64, 1275067264u64, - 1283453312u64, 1291844992u64, 1300234112u64, 1308619904u64, 1317010048u64, - 1325397376u64, 1333787776u64, 1342176128u64, 1350561664u64, 1358954368u64, - 1367339392u64, 1375731584u64, 1384118144u64, 1392507008u64, 1400897408u64, - 1409284736u64, 1417673344u64, 1426062464u64, 1434451072u64, 1442839168u64, - 1451229056u64, 1459615616u64, 1468006016u64, 1476394112u64, 1484782976u64, - 1493171584u64, 1501559168u64, 1509948032u64, 1518337664u64, 1526726528u64, - 1535114624u64, 1543503488u64, 1551892096u64, 1560278656u64, 1568669056u64, - 1577056384u64, 1585446272u64, 1593831296u64, 1602219392u64, 1610610304u64, - 1619000192u64, 1627386752u64, 1635773824u64, 1644164224u64, 1652555648u64, - 1660943488u64, 1669332608u64, 1677721216u64, 1686109312u64, 1694497664u64, - 1702886272u64, 1711274624u64, 1719661184u64, 1728047744u64, 1736434816u64, - 1744829056u64, 1753218944u64, 1761606272u64, 1769995904u64, 1778382464u64, - 1786772864u64, 1795157888u64, 1803550592u64, 1811937664u64, 1820327552u64, - 1828711552u64, 1837102976u64, 1845488768u64, 1853879936u64, 1862269312u64, - 1870656896u64, 1879048064u64, 1887431552u64, 1895825024u64, 1904212096u64, - 1912601216u64, 1920988544u64, 1929379456u64, 1937765504u64, 1946156672u64, - 1954543232u64, 1962932096u64, 1971321728u64, 1979707264u64, 1988093056u64, - 1996487552u64, 2004874624u64, 2013262208u64, 2021653888u64, 2030039936u64, - 2038430848u64, 2046819968u64, 2055208576u64, 2063596672u64, 2071981952u64, - 2080373632u64, 2088762752u64, 2097149056u64, 2105539712u64, 2113928576u64, - 2122315136u64, 2130700672u64, 2139092608u64, 2147483264u64, 2155872128u64, - 2164257664u64, 2172642176u64, 2181035392u64, 2189426048u64, 2197814912u64, - 2206203008u64, 2214587264u64, 2222979712u64, 2231367808u64, 2239758208u64, - 2248145024u64, 2256527744u64, 2264922752u64, 2273312128u64, 2281701248u64, - 2290086272u64, 2298476672u64, 2306867072u64, 2315251072u64, 2323639168u64, - 2332032128u64, 2340420224u64, 2348808064u64, 2357196416u64, 2365580416u64, - 2373966976u64, 2382363008u64, 2390748544u64, 2399139968u64, 2407530368u64, - 2415918976u64, 2424307328u64, 2432695424u64, 2441084288u64, 2449472384u64, - 2457861248u64, 2466247808u64, 2474637184u64, 2483026816u64, 2491414144u64, - 2499803776u64, 2508191872u64, 2516582272u64, 2524970368u64, 2533359232u64, - 2541743488u64, 2550134144u64, 2558525056u64, 2566913408u64, 2575301504u64, - 2583686528u64, 2592073856u64, 2600467328u64, 2608856192u64, 2617240448u64, - 2625631616u64, 2634022016u64, 2642407552u64, 2650796416u64, 2659188352u64, - 2667574912u64, 2675965312u64, 2684352896u64, 2692738688u64, 2701130624u64, - 2709518464u64, 2717907328u64, 2726293376u64, 2734685056u64, 2743073152u64, - 2751462016u64, 2759851648u64, 2768232832u64, 2776625536u64, 2785017728u64, - 2793401984u64, 2801794432u64, 2810182016u64, 2818571648u64, 2826959488u64, - 2835349376u64, 2843734144u64, 2852121472u64, 2860514432u64, 2868900992u64, - 2877286784u64, 2885676928u64, 2894069632u64, 2902451584u64, 2910843008u64, - 2919234688u64, 2927622784u64, 2936011648u64, 2944400768u64, 2952789376u64, - 2961177728u64, 2969565568u64, 2977951616u64, 2986338944u64, 2994731392u64, - 3003120256u64, 3011508352u64, 3019895936u64, 3028287104u64, 3036675968u64, - 3045063808u64, 3053452928u64, 3061837696u64, 3070228352u64, 3078615424u64, - 3087003776u64, 3095394944u64, 3103782272u64, 3112173184u64, 3120562048u64, - 3128944768u64, 3137339264u64, 3145725056u64, 3154109312u64, 3162505088u64, - 3170893184u64, 3179280256u64, 3187669376u64, 3196056704u64, 3204445568u64, - 3212836736u64, 3221224064u64, 3229612928u64, 3238002304u64, 3246391168u64, - 3254778496u64, 3263165824u64, 3271556224u64, 3279944576u64, 3288332416u64, - 3296719232u64, 3305110912u64, 3313500032u64, 3321887104u64, 3330273152u64, - 3338658944u64, 3347053184u64, 3355440512u64, 3363827072u64, 3372220288u64, - 3380608384u64, 3388997504u64, 3397384576u64, 3405774208u64, 3414163072u64, - 3422551936u64, 3430937984u64, 3439328384u64, 3447714176u64, 3456104576u64, - 3464493952u64, 3472883584u64, 3481268864u64, 3489655168u64, 3498048896u64, - 3506434432u64, 3514826368u64, 3523213952u64, 3531603584u64, 3539987072u64, - 3548380288u64, 3556763264u64, 3565157248u64, 3573545344u64, 3581934464u64, - 3590324096u64, 3598712704u64, 3607098752u64, 3615488384u64, 3623877248u64, - 3632265856u64, 3640646528u64, 3649043584u64, 3657430144u64, 3665821568u64, - 3674207872u64, 3682597504u64, 3690984832u64, 3699367808u64, 3707764352u64, - 3716152448u64, 3724541056u64, 3732925568u64, 3741318016u64, 3749706368u64, - 3758091136u64, 3766481536u64, 3774872704u64, 3783260032u64, 3791650432u64, - 3800036224u64, 3808427648u64, 3816815488u64, 3825204608u64, 3833592704u64, - 3841981568u64, 3850370432u64, 3858755968u64, 3867147904u64, 3875536256u64, - 3883920512u64, 3892313728u64, 3900702592u64, 3909087872u64, 3917478784u64, - 3925868416u64, 3934256512u64, 3942645376u64, 3951032192u64, 3959422336u64, - 3967809152u64, 3976200064u64, 3984588416u64, 3992974976u64, 4001363584u64, - 4009751168u64, 4018141312u64, 4026530432u64, 4034911616u64, 4043308928u64, - 4051695488u64, 4060084352u64, 4068472448u64, 4076862848u64, 4085249408u64, - 4093640576u64, 4102028416u64, 4110413696u64, 4118805632u64, 4127194496u64, - 4135583104u64, 4143971968u64, 4152360832u64, 4160746112u64, 4169135744u64, - 4177525888u64, 4185912704u64, 4194303616u64, 4202691968u64, 4211076736u64, - 4219463552u64, 4227855488u64, 4236246656u64, 4244633728u64, 4253022848u64, - 4261412224u64, 4269799808u64, 4278184832u64, 4286578048u64, 4294962304u64, - 4303349632u64, 4311743104u64, 4320130432u64, 4328521088u64, 4336909184u64, - 4345295488u64, 4353687424u64, 4362073472u64, 4370458496u64, 4378852736u64, - 4387238528u64, 4395630208u64, 4404019072u64, 4412407424u64, 4420790656u64, - 4429182848u64, 4437571456u64, 4445962112u64, 4454344064u64, 4462738048u64, - 4471119232u64, 4479516544u64, 4487904128u64, 4496289664u64, 4504682368u64, - 4513068416u64, 4521459584u64, 4529846144u64, 4538232704u64, 4546619776u64, - 4555010176u64, 4563402112u64, 4571790208u64, 4580174464u64, 4588567936u64, - 4596957056u64, 4605344896u64, 4613734016u64, 4622119808u64, 4630511488u64, - 4638898816u64, 4647287936u64, 4655675264u64, 4664065664u64, 4672451968u64, - 4680842624u64, 4689231488u64, 4697620352u64, 4706007424u64, 4714397056u64, - 4722786176u64, 4731173248u64, 4739562368u64, 4747951744u64, 4756340608u64, - 4764727936u64, 4773114496u64, 4781504384u64, 4789894784u64, 4798283648u64, - 4806667648u64, 4815059584u64, 4823449472u64, 4831835776u64, 4840226176u64, - 4848612224u64, 4857003392u64, 4865391488u64, 4873780096u64, 4882169728u64, - 4890557312u64, 4898946944u64, 4907333248u64, 4915722368u64, 4924110976u64, - 4932499328u64, 4940889728u64, 4949276032u64, 4957666432u64, 4966054784u64, - 4974438016u64, 4982831488u64, 4991221376u64, 4999607168u64, 5007998848u64, - 5016386432u64, 5024763776u64, 5033164672u64, 5041544576u64, 5049941888u64, - 5058329728u64, 5066717056u64, 5075107456u64, 5083494272u64, 5091883904u64, - 5100273536u64, 5108662144u64, 5117048192u64, 5125436032u64, 5133827456u64, - 5142215296u64, 5150605184u64, 5158993024u64, 5167382144u64, 5175769472u64, - 5184157568u64, 5192543872u64, 5200936064u64, 5209324928u64, 5217711232u64, - 5226102656u64, 5234490496u64, 5242877312u64, 5251263872u64, 5259654016u64, - 5268040832u64, 5276434304u64, 5284819328u64, 5293209728u64, 5301598592u64, - 5309986688u64, 5318374784u64, 5326764416u64, 5335151488u64, 5343542144u64, - 5351929472u64, 5360319872u64, 5368706944u64, 5377096576u64, 5385484928u64, - 5393871232u64, 5402263424u64, 5410650496u64, 5419040384u64, 5427426944u64, - 5435816576u64, 5444205952u64, 5452594816u64, 5460981376u64, 5469367936u64, - 5477760896u64, 5486148736u64, 5494536832u64, 5502925952u64, 5511315328u64, - 5519703424u64, 5528089984u64, 5536481152u64, 5544869504u64, 5553256064u64, - 5561645696u64, 5570032768u64, 5578423936u64, 5586811264u64, 5595193216u64, - 5603585408u64, 5611972736u64, 5620366208u64, 5628750464u64, 5637143936u64, - 5645528192u64, 5653921408u64, 5662310272u64, 5670694784u64, 5679082624u64, - 5687474048u64, 5695864448u64, 5704251008u64, 5712641408u64, 5721030272u64, - 5729416832u64, 5737806208u64, 5746194304u64, 5754583936u64, 5762969984u64, - 5771358592u64, 5779748224u64, 5788137856u64, 5796527488u64, 5804911232u64, - 5813300608u64, 5821692544u64, 5830082176u64, 5838468992u64, 5846855552u64, - 5855247488u64, 5863636096u64, 5872024448u64, 5880411008u64, 5888799872u64, - 5897186432u64, 5905576832u64, 5913966976u64, 5922352768u64, 5930744704u64, - 5939132288u64, 5947522432u64, 5955911296u64, 5964299392u64, 5972688256u64, - 5981074304u64, 5989465472u64, 5997851008u64, 6006241408u64, 6014627968u64, - 6023015552u64, 6031408256u64, 6039796096u64, 6048185216u64, 6056574848u64, - 6064963456u64, 6073351808u64, 6081736064u64, 6090128768u64, 6098517632u64, - 6106906496u64, 6115289216u64, 6123680896u64, 6132070016u64, 6140459648u64, - 6148849024u64, 6157237376u64, 6165624704u64, 6174009728u64, 6182403712u64, - 6190792064u64, 6199176064u64, 6207569792u64, 6215952256u64, 6224345216u64, - 6232732544u64, 6241124224u64, 6249510272u64, 6257899136u64, 6266287744u64, - 6274676864u64, 6283065728u64, 6291454336u64, 6299843456u64, 6308232064u64, - 6316620928u64, 6325006208u64, 6333395584u64, 6341784704u64, 6350174848u64, - 6358562176u64, 6366951296u64, 6375337856u64, 6383729536u64, 6392119168u64, - 6400504192u64, 6408895616u64, 6417283456u64, 6425673344u64, 6434059136u64, - 6442444672u64, 6450837376u64, 6459223424u64, 6467613056u64, 6476004224u64, - 6484393088u64, 6492781952u64, 6501170048u64, 6509555072u64, 6517947008u64, - 6526336384u64, 6534725504u64, 6543112832u64, 6551500672u64, 6559888768u64, - 6568278656u64, 6576662912u64, 6585055616u64, 6593443456u64, 6601834112u64, - 6610219648u64, 6618610304u64, 6626999168u64, 6635385472u64, 6643777408u64, - 6652164224u64, 6660552832u64, 6668941952u64, 6677330048u64, 6685719424u64, - 6694107776u64, 6702493568u64, 6710882176u64, 6719274112u64, 6727662976u64, - 6736052096u64, 6744437632u64, 6752825984u64, 6761213824u64, 6769604224u64, - 6777993856u64, 6786383488u64, 6794770816u64, 6803158144u64, 6811549312u64, - 6819937664u64, 6828326528u64, 6836706176u64, 6845101696u64, 6853491328u64, - 6861880448u64, 6870269312u64, 6878655104u64, 6887046272u64, 6895433344u64, - 6903822208u64, 6912212864u64, 6920596864u64, 6928988288u64, 6937377152u64, - 6945764992u64, 6954149248u64, 6962544256u64, 6970928768u64, 6979317376u64, - 6987709312u64, 6996093824u64, 7004487296u64, 7012875392u64, 7021258624u64, - 7029652352u64, 7038038912u64, 7046427776u64, 7054818944u64, 7063207808u64, - 7071595136u64, 7079980928u64, 7088372608u64, 7096759424u64, 7105149824u64, - 7113536896u64, 7121928064u64, 7130315392u64, 7138699648u64, 7147092352u64, - 7155479168u64, 7163865728u64, 7172249984u64, 7180648064u64, 7189036672u64, - 7197424768u64, 7205810816u64, 7214196608u64, 7222589824u64, 7230975104u64, - 7239367552u64, 7247755904u64, 7256145536u64, 7264533376u64, 7272921472u64, - 7281308032u64, 7289694848u64, 7298088832u64, 7306471808u64, 7314864512u64, - 7323253888u64, 7331643008u64, 7340029568u64, 7348419712u64, 7356808832u64, - 7365196672u64, 7373585792u64, 7381973888u64, 7390362752u64, 7398750592u64, - 7407138944u64, 7415528576u64, 7423915648u64, 7432302208u64, 7440690304u64, - 7449080192u64, 7457472128u64, 7465860992u64, 7474249088u64, 7482635648u64, - 7491023744u64, 7499412608u64, 7507803008u64, 7516192384u64, 7524579968u64, - 7532967296u64, 7541358464u64, 7549745792u64, 7558134656u64, 7566524032u64, - 7574912896u64, 7583300992u64, 7591690112u64, 7600075136u64, 7608466816u64, - 7616854912u64, 7625244544u64, 7633629824u64, 7642020992u64, 7650410368u64, - 7658794112u64, 7667187328u64, 7675574912u64, 7683961984u64, 7692349568u64, - 7700739712u64, 7709130368u64, 7717519232u64, 7725905536u64, 7734295424u64, - 7742683264u64, 7751069056u64, 7759457408u64, 7767849088u64, 7776238208u64, - 7784626816u64, 7793014912u64, 7801405312u64, 7809792128u64, 7818179968u64, - 7826571136u64, 7834957184u64, 7843347328u64, 7851732352u64, 7860124544u64, - 7868512384u64, 7876902016u64, 7885287808u64, 7893679744u64, 7902067072u64, - 7910455936u64, 7918844288u64, 7927230848u64, 7935622784u64, 7944009344u64, - 7952400256u64, 7960786048u64, 7969176704u64, 7977565312u64, 7985953408u64, - 7994339968u64, 8002730368u64, 8011119488u64, 8019508096u64, 8027896192u64, - 8036285056u64, 8044674688u64, 8053062272u64, 8061448832u64, 8069838464u64, - 8078227328u64, 8086616704u64, 8095006592u64, 8103393664u64, 8111783552u64, - 8120171392u64, 8128560256u64, 8136949376u64, 8145336704u64, 8153726848u64, - 8162114944u64, 8170503296u64, 8178891904u64, 8187280768u64, 8195669632u64, - 8204058496u64, 8212444544u64, 8220834176u64, 8229222272u64, 8237612672u64, - 8246000768u64, 8254389376u64, 8262775168u64, 8271167104u64, 8279553664u64, - 8287944064u64, 8296333184u64, 8304715136u64, 8313108352u64, 8321497984u64, - 8329885568u64, 8338274432u64, 8346663296u64, 8355052928u64, 8363441536u64, - 8371828352u64, 8380217984u64, 8388606592u64, 8396996224u64, 8405384576u64, - 8413772672u64, 8422161536u64, 8430549376u64, 8438939008u64, 8447326592u64, - 8455715456u64, 8464104832u64, 8472492928u64, 8480882048u64, 8489270656u64, - 8497659776u64, 8506045312u64, 8514434944u64, 8522823808u64, 8531208832u64, - 8539602304u64, 8547990656u64, 8556378752u64, 8564768384u64, 8573154176u64, - 8581542784u64, 8589933952u64, 8598322816u64, 8606705024u64, 8615099264u64, - 8623487872u64, 8631876992u64, 8640264064u64, 8648653952u64, 8657040256u64, - 8665430656u64, 8673820544u64, 8682209152u64, 8690592128u64, 8698977152u64, - 8707374464u64, 8715763328u64, 8724151424u64, 8732540032u64, 8740928384u64, - 8749315712u64, 8757704576u64, 8766089344u64, 8774480768u64, 8782871936u64, - 8791260032u64, 8799645824u64, 8808034432u64, 8816426368u64, 8824812928u64, - 8833199488u64, 8841591424u64, 8849976448u64, 8858366336u64, 8866757248u64, - 8875147136u64, 8883532928u64, 8891923328u64, 8900306816u64, 8908700288u64, - 8917088384u64, 8925478784u64, 8933867392u64, 8942250368u64, 8950644608u64, - 8959032704u64, 8967420544u64, 8975809664u64, 8984197504u64, 8992584064u64, - 9000976256u64, 9009362048u64, 9017752448u64, 9026141312u64, 9034530688u64, - 9042917504u64, 9051307904u64, 9059694208u64, 9068084864u64, 9076471424u64, - 9084861824u64, 9093250688u64, 9101638528u64, 9110027648u64, 9118416512u64, - 9126803584u64, 9135188096u64, 9143581312u64, 9151969664u64, 9160356224u64, - 9168747136u64, 9177134464u64, 9185525632u64, 9193910144u64, 9202302848u64, - 9210690688u64, 9219079552u64, 9227465344u64, 9235854464u64, 9244244864u64, - 9252633472u64, 9261021824u64, 9269411456u64, 9277799296u64, 9286188928u64, - 9294574208u64, 9302965888u64, 9311351936u64, 9319740032u64, 9328131968u64, - 9336516736u64, 9344907392u64, 9353296768u64, 9361685888u64, 9370074752u64, - 9378463616u64, 9386849408u64, 9395239808u64, 9403629184u64, 9412016512u64, - 9420405376u64, 9428795008u64, 9437181568u64, 9445570688u64, 9453960832u64, - 9462346624u64, 9470738048u64, 9479121536u64, 9487515008u64, 9495903616u64, - 9504289664u64, 9512678528u64, 9521067904u64, 9529456256u64, 9537843584u64, - 9546233728u64, 9554621312u64, 9563011456u64, 9571398784u64, 9579788672u64, - 9588178304u64, 9596567168u64, 9604954496u64, 9613343104u64, 9621732992u64, - 9630121856u64, 9638508416u64, 9646898816u64, 9655283584u64, 9663675776u64, - 9672061312u64, 9680449664u64, 9688840064u64, 9697230464u64, 9705617536u64, - 9714003584u64, 9722393984u64, 9730772608u64, 9739172224u64, 9747561088u64, - 9755945344u64, 9764338816u64, 9772726144u64, 9781116544u64, 9789503872u64, - 9797892992u64, 9806282624u64, 9814670464u64, 9823056512u64, 9831439232u64, - 9839833984u64, 9848224384u64, 9856613504u64, 9865000576u64, 9873391232u64, - 9881772416u64, 9890162816u64, 9898556288u64, 9906940544u64, 9915333248u64, - 9923721088u64, 9932108672u64, 9940496512u64, 9948888448u64, 9957276544u64, - 9965666176u64, 9974048384u64, 9982441088u64, 9990830464u64, 9999219584u64, - 10007602816u64, 10015996544u64, 10024385152u64, 10032774016u64, 10041163648u64, - 10049548928u64, 10057940096u64, 10066329472u64, 10074717824u64, 10083105152u64, - 10091495296u64, 10099878784u64, 10108272256u64, 10116660608u64, 10125049216u64, - 10133437312u64, 10141825664u64, 10150213504u64, 10158601088u64, 10166991232u64, - 10175378816u64, 10183766144u64, 10192157312u64, 10200545408u64, 10208935552u64, - 10217322112u64, 10225712768u64, 10234099328u64, 10242489472u64, 10250876032u64, - 10259264896u64, 10267656064u64, 10276042624u64, 10284429184u64, 10292820352u64, - 10301209472u64, 10309598848u64, 10317987712u64, 10326375296u64, 10334763392u64, - 10343153536u64, 10351541632u64, 10359930752u64, 10368318592u64, 10376707456u64, - 10385096576u64, 10393484672u64, 10401867136u64, 10410262144u64, 10418647424u64, - 10427039104u64, 10435425664u64, 10443810176u64, 10452203648u64, 10460589952u64, - 10468982144u64, 10477369472u64, 10485759104u64, 10494147712u64, 10502533504u64, - 10510923392u64, 10519313536u64, 10527702656u64, 10536091264u64, 10544478592u64, - 10552867712u64, 10561255808u64, 10569642368u64, 10578032768u64, 10586423168u64, - 10594805632u64, 10603200128u64, 10611588992u64, 10619976064u64, 10628361344u64, - 10636754048u64, 10645143424u64, 10653531776u64, 10661920384u64, 10670307968u64, - 10678696832u64, 10687086464u64, 10695475072u64, 10703863168u64, 10712246144u64, - 10720639616u64, 10729026688u64, 10737414784u64, 10745806208u64, 10754190976u64, - 10762581376u64, 10770971264u64, 10779356288u64, 10787747456u64, 10796135552u64, - 10804525184u64, 10812915584u64, 10821301888u64, 10829692288u64, 10838078336u64, - 10846469248u64, 10854858368u64, 10863247232u64, 10871631488u64, 10880023424u64, - 10888412032u64, 10896799616u64, 10905188992u64, 10913574016u64, 10921964672u64, - 10930352768u64, 10938742912u64, 10947132544u64, 10955518592u64, 10963909504u64, - 10972298368u64, 10980687488u64, 10989074816u64, 10997462912u64, 11005851776u64, - 11014241152u64, 11022627712u64, 11031017344u64, 11039403904u64, 11047793024u64, - 11056184704u64, 11064570752u64, 11072960896u64, 11081343872u64, 11089737856u64, - 11098128256u64, 11106514816u64, 11114904448u64, 11123293568u64, 11131680128u64, - 11140065152u64, 11148458368u64, 11156845696u64, 11165236864u64, 11173624192u64, - 11182013824u64, 11190402688u64, 11198790784u64, 11207179136u64, 11215568768u64, - 11223957376u64, 11232345728u64, 11240734592u64, 11249122688u64, 11257511296u64, - 11265899648u64, 11274285952u64, 11282675584u64, 11291065472u64, 11299452544u64, - 11307842432u64, 11316231296u64, 11324616832u64, 11333009024u64, 11341395584u64, - 11349782656u64, 11358172288u64, 11366560384u64, 11374950016u64, 11383339648u64, - 11391721856u64, 11400117376u64, 11408504192u64, 11416893568u64, 11425283456u64, - 11433671552u64, 11442061184u64, 11450444672u64, 11458837888u64, 11467226752u64, - 11475611776u64, 11484003968u64, 11492392064u64, 11500780672u64, 11509169024u64, - 11517550976u64, 11525944448u64, 11534335616u64, 11542724224u64, 11551111808u64, - 11559500672u64, 11567890304u64, 11576277376u64, 11584667008u64, 11593056128u64, - 11601443456u64, 11609830016u64, 11618221952u64, 11626607488u64, 11634995072u64, - 11643387776u64, 11651775104u64, 11660161664u64, 11668552576u64, 11676940928u64, - 11685330304u64, 11693718656u64, 11702106496u64, 11710496128u64, 11718882688u64, - 11727273088u64, 11735660416u64, 11744050048u64, 11752437376u64, 11760824704u64, - 11769216128u64, 11777604736u64, 11785991296u64, 11794381952u64, 11802770048u64, - 11811157888u64, 11819548544u64, 11827932544u64, 11836324736u64, 11844713344u64, - 11853100928u64, 11861486464u64, 11869879936u64, 11878268032u64, 11886656896u64, - 11895044992u64, 11903433088u64, 11911822976u64, 11920210816u64, 11928600448u64, - 11936987264u64, 11945375872u64, 11953761152u64, 11962151296u64, 11970543488u64, - 11978928512u64, 11987320448u64, 11995708288u64, 12004095104u64, 12012486272u64, - 12020875136u64, 12029255552u64, 12037652096u64, 12046039168u64, 12054429568u64, - 12062813824u64, 12071206528u64, 12079594624u64, 12087983744u64, 12096371072u64, - 12104759936u64, 12113147264u64, 12121534592u64, 12129924992u64, 12138314624u64, - 12146703232u64, 12155091584u64, 12163481216u64, 12171864704u64, 12180255872u64, - 12188643968u64, 12197034112u64, 12205424512u64, 12213811328u64, 12222199424u64, - 12230590336u64, 12238977664u64, 12247365248u64, 12255755392u64, 12264143488u64, - 12272531584u64, 12280920448u64, 12289309568u64, 12297694592u64, 12306086528u64, - 12314475392u64, 12322865024u64, 12331253632u64, 12339640448u64, 12348029312u64, - 12356418944u64, 12364805248u64, 12373196672u64, 12381580928u64, 12389969024u64, - 12398357632u64, 12406750592u64, 12415138432u64, 12423527552u64, 12431916416u64, - 12440304512u64, 12448692352u64, 12457081216u64, 12465467776u64, 12473859968u64, - 12482245504u64, 12490636672u64, 12499025536u64, 12507411584u64, 12515801728u64, - 12524190592u64, 12532577152u64, 12540966272u64, 12549354368u64, 12557743232u64, - 12566129536u64, 12574523264u64, 12582911872u64, 12591299456u64, 12599688064u64, - 12608074624u64, 12616463488u64, 12624845696u64, 12633239936u64, 12641631616u64, - 12650019968u64, 12658407296u64, 12666795136u64, 12675183232u64, 12683574656u64, - 12691960192u64, 12700350592u64, 12708740224u64, 12717128576u64, 12725515904u64, - 12733906816u64, 12742295168u64, 12750680192u64, 12759071872u64, 12767460736u64, - 12775848832u64, 12784236928u64, 12792626816u64, 12801014656u64, 12809404288u64, - 12817789312u64, 12826181504u64, 12834568832u64, 12842954624u64, 12851345792u64, - 12859732352u64, 12868122496u64, 12876512128u64, 12884901248u64, 12893289088u64, - 12901672832u64, 12910067584u64, 12918455168u64, 12926842496u64, 12935232896u64, - 12943620736u64, 12952009856u64, 12960396928u64, 12968786816u64, 12977176192u64, - 12985563776u64, 12993951104u64, 13002341504u64, 13010730368u64, 13019115392u64, - 13027506304u64, 13035895168u64, 13044272512u64, 13052673152u64, 13061062528u64, - 13069446272u64, 13077838976u64, 13086227072u64, 13094613632u64, 13103000192u64, - 13111393664u64, 13119782528u64, 13128157568u64, 13136559232u64, 13144945024u64, - 13153329536u64, 13161724288u64, 13170111872u64, 13178502784u64, 13186884736u64, - 13195279744u64, 13203667072u64, 13212057472u64, 13220445824u64, 13228832128u64, - 13237221248u64, 13245610624u64, 13254000512u64, 13262388352u64, 13270777472u64, - 13279166336u64, 13287553408u64, 13295943296u64, 13304331904u64, 13312719488u64, - 13321108096u64, 13329494656u64, 13337885824u64, 13346274944u64, 13354663808u64, - 13363051136u64, 13371439232u64, 13379825024u64, 13388210816u64, 13396605056u64, - 13404995456u64, 13413380224u64, 13421771392u64, 13430159744u64, 13438546048u64, - 13446937216u64, 13455326848u64, 13463708288u64, 13472103808u64, 13480492672u64, - 13488875648u64, 13497269888u64, 13505657728u64, 13514045312u64, 13522435712u64, - 13530824576u64, 13539210112u64, 13547599232u64, 13555989376u64, 13564379008u64, - 13572766336u64, 13581154432u64, 13589544832u64, 13597932928u64, 13606320512u64, - 13614710656u64, 13623097472u64, 13631477632u64, 13639874944u64, 13648264064u64, - 13656652928u64, 13665041792u64, 13673430656u64, 13681818496u64, 13690207616u64, - 13698595712u64, 13706982272u64, 13715373184u64, 13723762048u64, 13732150144u64, - 13740536704u64, 13748926592u64, 13757316224u64, 13765700992u64, 13774090112u64, - 13782477952u64, 13790869376u64, 13799259008u64, 13807647872u64, 13816036736u64, - 13824425344u64, 13832814208u64, 13841202304u64, 13849591424u64, 13857978752u64, - 13866368896u64, 13874754688u64, 13883145344u64, 13891533184u64, 13899919232u64, - 13908311168u64, 13916692096u64, 13925085056u64, 13933473152u64, 13941866368u64, - 13950253696u64, 13958643584u64, 13967032192u64, 13975417216u64, 13983807616u64, - 13992197504u64, 14000582272u64, 14008973696u64, 14017363072u64, 14025752192u64, - 14034137984u64, 14042528384u64, 14050918016u64, 14059301504u64, 14067691648u64, - 14076083584u64, 14084470144u64, 14092852352u64, 14101249664u64, 14109635968u64, - 14118024832u64, 14126407552u64, 14134804352u64, 14143188608u64, 14151577984u64, - 14159968384u64, 14168357248u64, 14176741504u64, 14185127296u64, 14193521024u64, - 14201911424u64, 14210301824u64, 14218685056u64, 14227067264u64, 14235467392u64, - 14243855488u64, 14252243072u64, 14260630144u64, 14269021568u64, 14277409408u64, - 14285799296u64, 14294187904u64, 14302571392u64, 14310961792u64, 14319353728u64, - 14327738752u64, 14336130944u64, 14344518784u64, 14352906368u64, 14361296512u64, - 14369685376u64, 14378071424u64, 14386462592u64, 14394848128u64, 14403230848u64, - 14411627392u64, 14420013952u64, 14428402304u64, 14436793472u64, 14445181568u64, - 14453569664u64, 14461959808u64, 14470347904u64, 14478737024u64, 14487122816u64, - 14495511424u64, 14503901824u64, 14512291712u64, 14520677504u64, 14529064832u64, - 14537456768u64, 14545845632u64, 14554234496u64, 14562618496u64, 14571011456u64, - 14579398784u64, 14587789184u64, 14596172672u64, 14604564608u64, 14612953984u64, - 14621341312u64, 14629724288u64, 14638120832u64, 14646503296u64, 14654897536u64, - 14663284864u64, 14671675264u64, 14680061056u64, 14688447616u64, 14696835968u64, - 14705228416u64, 14713616768u64, 14722003328u64, 14730392192u64, 14738784128u64, - 14747172736u64, 14755561088u64, 14763947648u64, 14772336512u64, 14780725376u64, - 14789110144u64, 14797499776u64, 14805892736u64, 14814276992u64, 14822670208u64, - 14831056256u64, 14839444352u64, 14847836032u64, 14856222848u64, 14864612992u64, - 14872997504u64, 14881388672u64, 14889775744u64, 14898165376u64, 14906553472u64, - 14914944896u64, 14923329664u64, 14931721856u64, 14940109696u64, 14948497024u64, - 14956887424u64, 14965276544u64, 14973663616u64, 14982053248u64, 14990439808u64, - 14998830976u64, 15007216768u64, 15015605888u64, 15023995264u64, 15032385152u64, - 15040768384u64, 15049154944u64, 15057549184u64, 15065939072u64, 15074328448u64, - 15082715008u64, 15091104128u64, 15099493504u64, 15107879296u64, 15116269184u64, - 15124659584u64, 15133042304u64, 15141431936u64, 15149824384u64, 15158214272u64, - 15166602368u64, 15174991232u64, 15183378304u64, 15191760512u64, 15200154496u64, - 15208542592u64, 15216931712u64, 15225323392u64, 15233708416u64, 15242098048u64, - 15250489216u64, 15258875264u64, 15267265408u64, 15275654528u64, 15284043136u64, - 15292431488u64, 15300819584u64, 15309208192u64, 15317596544u64, 15325986176u64, - 15334374784u64, 15342763648u64, 15351151744u64, 15359540608u64, 15367929728u64, - 15376318336u64, 15384706432u64, 15393092992u64, 15401481856u64, 15409869952u64, - 15418258816u64, 15426649984u64, 15435037568u64, 15443425664u64, 15451815296u64, - 15460203392u64, 15468589184u64, 15476979328u64, 15485369216u64, 15493755776u64, - 15502146944u64, 15510534272u64, 15518924416u64, 15527311232u64, 15535699072u64, - 15544089472u64, 15552478336u64, 15560866688u64, 15569254528u64, 15577642624u64, - 15586031488u64, 15594419072u64, 15602809472u64, 15611199104u64, 15619586432u64, - 15627975296u64, 15636364928u64, 15644753792u64, 15653141888u64, 15661529216u64, - 15669918848u64, 15678305152u64, 15686696576u64, 15695083136u64, 15703474048u64, - 15711861632u64, 15720251264u64, 15728636288u64, 15737027456u64, 15745417088u64, - 15753804928u64, 15762194048u64, 15770582656u64, 15778971008u64, 15787358336u64, - 15795747712u64, 15804132224u64, 15812523392u64, 15820909696u64, 15829300096u64, - 15837691264u64, 15846071936u64, 15854466944u64, 15862855808u64, 15871244672u64, - 15879634816u64, 15888020608u64, 15896409728u64, 15904799104u64, 15913185152u64, - 15921577088u64, 15929966464u64, 15938354816u64, 15946743424u64, 15955129472u64, - 15963519872u64, 15971907968u64, 15980296064u64, 15988684928u64, 15997073024u64, - 16005460864u64, 16013851264u64, 16022241152u64, 16030629248u64, 16039012736u64, - 16047406976u64, 16055794816u64, 16064181376u64, 16072571264u64, 16080957824u64, - 16089346688u64, 16097737856u64, 16106125184u64, 16114514816u64, 16122904192u64, - 16131292544u64, 16139678848u64, 16148066944u64, 16156453504u64, 16164839552u64, - 16173236096u64, 16181623424u64, 16190012032u64, 16198401152u64, 16206790528u64, - 16215177344u64, 16223567744u64, 16231956352u64, 16240344704u64, 16248731008u64, - 16257117824u64, 16265504384u64, 16273898624u64, 16282281856u64, 16290668672u64, - 16299064192u64, 16307449216u64, 16315842176u64, 16324230016u64, 16332613504u64, - 16341006464u64, 16349394304u64, 16357783168u64, 16366172288u64, 16374561664u64, - 16382951296u64, 16391337856u64, 16399726208u64, 16408116352u64, 16416505472u64, - 16424892032u64, 16433282176u64, 16441668224u64, 16450058624u64, 16458448768u64, - 16466836864u64, 16475224448u64, 16483613056u64, 16492001408u64, 16500391808u64, - 16508779648u64, 16517166976u64, 16525555328u64, 16533944192u64, 16542330752u64, - 16550719616u64, 16559110528u64, 16567497088u64, 16575888512u64, 16584274816u64, - 16592665472u64, 16601051008u64, 16609442944u64, 16617832064u64, 16626218624u64, - 16634607488u64, 16642996096u64, 16651385728u64, 16659773824u64, 16668163712u64, - 16676552576u64, 16684938112u64, 16693328768u64, 16701718144u64, 16710095488u64, - 16718492288u64, 16726883968u64, 16735272832u64, 16743661184u64, 16752049792u64, - 16760436608u64, 16768827008u64, 16777214336u64, 16785599104u64, 16793992832u64, - 16802381696u64, 16810768768u64, 16819151744u64, 16827542656u64, 16835934848u64, - 16844323712u64, 16852711552u64, 16861101952u64, 16869489536u64, 16877876864u64, - 16886265728u64, 16894653056u64, 16903044736u64, 16911431296u64, 16919821696u64, - 16928207488u64, 16936592768u64, 16944987776u64, 16953375616u64, 16961763968u64, - 16970152832u64, 16978540928u64, 16986929536u64, 16995319168u64, 17003704448u64, - 17012096896u64, 17020481152u64, 17028870784u64, 17037262208u64, 17045649536u64, - 17054039936u64, 17062426496u64, 17070814336u64, 17079205504u64, 17087592064u64, - 17095978112u64, 17104369024u64, 17112759424u64, 17121147776u64, 17129536384u64, - 17137926016u64, 17146314368u64, 17154700928u64, 17163089792u64, 17171480192u64, - 17179864192u64, 17188256896u64, 17196644992u64, 17205033856u64, 17213423488u64, - 17221811072u64, 17230198912u64, 17238588032u64, 17246976896u64, 17255360384u64, - 17263754624u64, 17272143232u64, 17280530048u64, 17288918912u64, 17297309312u64, - 17305696384u64, 17314085504u64, 17322475136u64, 17330863744u64, 17339252096u64, - 17347640192u64, 17356026496u64, 17364413824u64, 17372796544u64, 17381190016u64, - 17389583488u64, 17397972608u64, 17406360704u64, 17414748544u64, 17423135872u64, - 17431527296u64, 17439915904u64, 17448303232u64, 17456691584u64, 17465081728u64, - 17473468288u64, 17481857408u64, 17490247552u64, 17498635904u64, 17507022464u64, - 17515409024u64, 17523801728u64, 17532189824u64, 17540577664u64, 17548966016u64, - 17557353344u64, 17565741184u64, 17574131584u64, 17582519168u64, 17590907008u64, - 17599296128u64, 17607687808u64, 17616076672u64, 17624455808u64, 17632852352u64, - 17641238656u64, 17649630848u64, 17658018944u64, 17666403968u64, 17674794112u64, - 17683178368u64, 17691573376u64, 17699962496u64, 17708350592u64, 17716739968u64, - 17725126528u64, 17733517184u64, 17741898112u64, 17750293888u64, 17758673024u64, - 17767070336u64, 17775458432u64, 17783848832u64, 17792236928u64, 17800625536u64, - 17809012352u64, 17817402752u64, 17825785984u64, 17834178944u64, 17842563968u64, - 17850955648u64, 17859344512u64, 17867732864u64, 17876119424u64, 17884511872u64, - 17892900224u64, 17901287296u64, 17909677696u64, 17918058112u64, 17926451072u64, - 17934843776u64, 17943230848u64, 17951609216u64, 17960008576u64, 17968397696u64, - 17976784256u64, 17985175424u64, 17993564032u64, 18001952128u64, 18010339712u64, - 18018728576u64, 18027116672u64, 18035503232u64, 18043894144u64, 18052283264u64, - 18060672128u64, 18069056384u64, 18077449856u64, 18085837184u64, 18094225792u64, - 18102613376u64, 18111004544u64, 18119388544u64, 18127781248u64, 18136170368u64, - 18144558976u64, 18152947328u64, 18161336192u64, 18169724288u64, 18178108544u64, - 18186498944u64, 18194886784u64, 18203275648u64, 18211666048u64, 18220048768u64, - 18228444544u64, 18236833408u64, 18245220736u64 -]; - -// Generated with the following Mathematica Code: - -// GetCacheSizes[n_] := Module[{ -// DataSetSizeBytesInit = 2^30, -// MixBytes = 128, -// DataSetGrowth = 2^23, -// HashBytes = 64, -// CacheMultiplier = 1024, -// j = 0}, -// Reap[ -// While[j < n, -// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]}, -// While[! PrimeQ[i], i--]; -// Sow[i*HashBytes]; j++]]]][[2]][[1]] -pub const CACHE_SIZES: [u64; 2048] = [ - 16776896u64, 16907456u64, 17039296u64, 17170112u64, 17301056u64, 17432512u64, 17563072u64, - 17693888u64, 17824192u64, 17955904u64, 18087488u64, 18218176u64, 18349504u64, 18481088u64, - 18611392u64, 18742336u64, 18874304u64, 19004224u64, 19135936u64, 19267264u64, 19398208u64, - 19529408u64, 19660096u64, 19791424u64, 19922752u64, 20053952u64, 20184896u64, 20315968u64, - 20446912u64, 20576576u64, 20709184u64, 20840384u64, 20971072u64, 21102272u64, 21233216u64, - 21364544u64, 21494848u64, 21626816u64, 21757376u64, 21887552u64, 22019392u64, 22151104u64, - 22281536u64, 22412224u64, 22543936u64, 22675264u64, 22806464u64, 22935872u64, 23068096u64, - 23198272u64, 23330752u64, 23459008u64, 23592512u64, 23723968u64, 23854912u64, 23986112u64, - 24116672u64, 24247616u64, 24378688u64, 24509504u64, 24640832u64, 24772544u64, 24903488u64, - 25034432u64, 25165376u64, 25296704u64, 25427392u64, 25558592u64, 25690048u64, 25820096u64, - 25951936u64, 26081728u64, 26214208u64, 26345024u64, 26476096u64, 26606656u64, 26737472u64, - 26869184u64, 26998208u64, 27131584u64, 27262528u64, 27393728u64, 27523904u64, 27655744u64, - 27786688u64, 27917888u64, 28049344u64, 28179904u64, 28311488u64, 28441792u64, 28573504u64, - 28700864u64, 28835648u64, 28966208u64, 29096768u64, 29228608u64, 29359808u64, 29490752u64, - 29621824u64, 29752256u64, 29882816u64, 30014912u64, 30144448u64, 30273728u64, 30406976u64, - 30538432u64, 30670784u64, 30799936u64, 30932672u64, 31063744u64, 31195072u64, 31325248u64, - 31456192u64, 31588288u64, 31719232u64, 31850432u64, 31981504u64, 32110784u64, 32243392u64, - 32372672u64, 32505664u64, 32636608u64, 32767808u64, 32897344u64, 33029824u64, 33160768u64, - 33289664u64, 33423296u64, 33554368u64, 33683648u64, 33816512u64, 33947456u64, 34076992u64, - 34208704u64, 34340032u64, 34471744u64, 34600256u64, 34734016u64, 34864576u64, 34993984u64, - 35127104u64, 35258176u64, 35386688u64, 35518528u64, 35650624u64, 35782336u64, 35910976u64, - 36044608u64, 36175808u64, 36305728u64, 36436672u64, 36568384u64, 36699968u64, 36830656u64, - 36961984u64, 37093312u64, 37223488u64, 37355072u64, 37486528u64, 37617472u64, 37747904u64, - 37879232u64, 38009792u64, 38141888u64, 38272448u64, 38403392u64, 38535104u64, 38660672u64, - 38795584u64, 38925632u64, 39059264u64, 39190336u64, 39320768u64, 39452096u64, 39581632u64, - 39713984u64, 39844928u64, 39974848u64, 40107968u64, 40238144u64, 40367168u64, 40500032u64, - 40631744u64, 40762816u64, 40894144u64, 41023552u64, 41155904u64, 41286208u64, 41418304u64, - 41547712u64, 41680448u64, 41811904u64, 41942848u64, 42073792u64, 42204992u64, 42334912u64, - 42467008u64, 42597824u64, 42729152u64, 42860096u64, 42991552u64, 43122368u64, 43253696u64, - 43382848u64, 43515712u64, 43646912u64, 43777088u64, 43907648u64, 44039104u64, 44170432u64, - 44302144u64, 44433344u64, 44564288u64, 44694976u64, 44825152u64, 44956864u64, 45088448u64, - 45219008u64, 45350464u64, 45481024u64, 45612608u64, 45744064u64, 45874496u64, 46006208u64, - 46136768u64, 46267712u64, 46399424u64, 46529344u64, 46660672u64, 46791488u64, 46923328u64, - 47053504u64, 47185856u64, 47316928u64, 47447872u64, 47579072u64, 47710144u64, 47839936u64, - 47971648u64, 48103232u64, 48234176u64, 48365248u64, 48496192u64, 48627136u64, 48757312u64, - 48889664u64, 49020736u64, 49149248u64, 49283008u64, 49413824u64, 49545152u64, 49675712u64, - 49807168u64, 49938368u64, 50069056u64, 50200256u64, 50331584u64, 50462656u64, 50593472u64, - 50724032u64, 50853952u64, 50986048u64, 51117632u64, 51248576u64, 51379904u64, 51510848u64, - 51641792u64, 51773248u64, 51903296u64, 52035136u64, 52164032u64, 52297664u64, 52427968u64, - 52557376u64, 52690112u64, 52821952u64, 52952896u64, 53081536u64, 53213504u64, 53344576u64, - 53475776u64, 53608384u64, 53738816u64, 53870528u64, 54000832u64, 54131776u64, 54263744u64, - 54394688u64, 54525248u64, 54655936u64, 54787904u64, 54918592u64, 55049152u64, 55181248u64, - 55312064u64, 55442752u64, 55574336u64, 55705024u64, 55836224u64, 55967168u64, 56097856u64, - 56228672u64, 56358592u64, 56490176u64, 56621888u64, 56753728u64, 56884928u64, 57015488u64, - 57146816u64, 57278272u64, 57409216u64, 57540416u64, 57671104u64, 57802432u64, 57933632u64, - 58064576u64, 58195264u64, 58326976u64, 58457408u64, 58588864u64, 58720192u64, 58849984u64, - 58981696u64, 59113024u64, 59243456u64, 59375552u64, 59506624u64, 59637568u64, 59768512u64, - 59897792u64, 60030016u64, 60161984u64, 60293056u64, 60423872u64, 60554432u64, 60683968u64, - 60817216u64, 60948032u64, 61079488u64, 61209664u64, 61341376u64, 61471936u64, 61602752u64, - 61733696u64, 61865792u64, 61996736u64, 62127808u64, 62259136u64, 62389568u64, 62520512u64, - 62651584u64, 62781632u64, 62910784u64, 63045056u64, 63176128u64, 63307072u64, 63438656u64, - 63569216u64, 63700928u64, 63831616u64, 63960896u64, 64093888u64, 64225088u64, 64355392u64, - 64486976u64, 64617664u64, 64748608u64, 64879424u64, 65009216u64, 65142464u64, 65273792u64, - 65402816u64, 65535424u64, 65666752u64, 65797696u64, 65927744u64, 66060224u64, 66191296u64, - 66321344u64, 66453056u64, 66584384u64, 66715328u64, 66846656u64, 66977728u64, 67108672u64, - 67239104u64, 67370432u64, 67501888u64, 67631296u64, 67763776u64, 67895104u64, 68026304u64, - 68157248u64, 68287936u64, 68419264u64, 68548288u64, 68681408u64, 68811968u64, 68942912u64, - 69074624u64, 69205568u64, 69337024u64, 69467584u64, 69599168u64, 69729472u64, 69861184u64, - 69989824u64, 70122944u64, 70253888u64, 70385344u64, 70515904u64, 70647232u64, 70778816u64, - 70907968u64, 71040832u64, 71171648u64, 71303104u64, 71432512u64, 71564992u64, 71695168u64, - 71826368u64, 71958464u64, 72089536u64, 72219712u64, 72350144u64, 72482624u64, 72613568u64, - 72744512u64, 72875584u64, 73006144u64, 73138112u64, 73268672u64, 73400128u64, 73530944u64, - 73662272u64, 73793344u64, 73924544u64, 74055104u64, 74185792u64, 74316992u64, 74448832u64, - 74579392u64, 74710976u64, 74841664u64, 74972864u64, 75102784u64, 75233344u64, 75364544u64, - 75497024u64, 75627584u64, 75759296u64, 75890624u64, 76021696u64, 76152256u64, 76283072u64, - 76414144u64, 76545856u64, 76676672u64, 76806976u64, 76937792u64, 77070016u64, 77200832u64, - 77331392u64, 77462464u64, 77593664u64, 77725376u64, 77856448u64, 77987776u64, 78118336u64, - 78249664u64, 78380992u64, 78511424u64, 78642496u64, 78773056u64, 78905152u64, 79033664u64, - 79166656u64, 79297472u64, 79429568u64, 79560512u64, 79690816u64, 79822784u64, 79953472u64, - 80084672u64, 80214208u64, 80346944u64, 80477632u64, 80608576u64, 80740288u64, 80870848u64, - 81002048u64, 81133504u64, 81264448u64, 81395648u64, 81525952u64, 81657536u64, 81786304u64, - 81919808u64, 82050112u64, 82181312u64, 82311616u64, 82443968u64, 82573376u64, 82705984u64, - 82835776u64, 82967744u64, 83096768u64, 83230528u64, 83359552u64, 83491264u64, 83622464u64, - 83753536u64, 83886016u64, 84015296u64, 84147776u64, 84277184u64, 84409792u64, 84540608u64, - 84672064u64, 84803008u64, 84934336u64, 85065152u64, 85193792u64, 85326784u64, 85458496u64, - 85589312u64, 85721024u64, 85851968u64, 85982656u64, 86112448u64, 86244416u64, 86370112u64, - 86506688u64, 86637632u64, 86769344u64, 86900672u64, 87031744u64, 87162304u64, 87293632u64, - 87424576u64, 87555392u64, 87687104u64, 87816896u64, 87947968u64, 88079168u64, 88211264u64, - 88341824u64, 88473152u64, 88603712u64, 88735424u64, 88862912u64, 88996672u64, 89128384u64, - 89259712u64, 89390272u64, 89521984u64, 89652544u64, 89783872u64, 89914816u64, 90045376u64, - 90177088u64, 90307904u64, 90438848u64, 90569152u64, 90700096u64, 90832832u64, 90963776u64, - 91093696u64, 91223744u64, 91356992u64, 91486784u64, 91618496u64, 91749824u64, 91880384u64, - 92012224u64, 92143552u64, 92273344u64, 92405696u64, 92536768u64, 92666432u64, 92798912u64, - 92926016u64, 93060544u64, 93192128u64, 93322816u64, 93453632u64, 93583936u64, 93715136u64, - 93845056u64, 93977792u64, 94109504u64, 94240448u64, 94371776u64, 94501184u64, 94632896u64, - 94764224u64, 94895552u64, 95023424u64, 95158208u64, 95287744u64, 95420224u64, 95550016u64, - 95681216u64, 95811904u64, 95943872u64, 96075328u64, 96203584u64, 96337856u64, 96468544u64, - 96599744u64, 96731072u64, 96860992u64, 96992576u64, 97124288u64, 97254848u64, 97385536u64, - 97517248u64, 97647808u64, 97779392u64, 97910464u64, 98041408u64, 98172608u64, 98303168u64, - 98434496u64, 98565568u64, 98696768u64, 98827328u64, 98958784u64, 99089728u64, 99220928u64, - 99352384u64, 99482816u64, 99614272u64, 99745472u64, 99876416u64, 100007104u64, - 100138048u64, 100267072u64, 100401088u64, 100529984u64, 100662592u64, 100791872u64, - 100925248u64, 101056064u64, 101187392u64, 101317952u64, 101449408u64, 101580608u64, - 101711296u64, 101841728u64, 101973824u64, 102104896u64, 102235712u64, 102366016u64, - 102498112u64, 102628672u64, 102760384u64, 102890432u64, 103021888u64, 103153472u64, - 103284032u64, 103415744u64, 103545152u64, 103677248u64, 103808576u64, 103939648u64, - 104070976u64, 104201792u64, 104332736u64, 104462528u64, 104594752u64, 104725952u64, - 104854592u64, 104988608u64, 105118912u64, 105247808u64, 105381184u64, 105511232u64, - 105643072u64, 105774784u64, 105903296u64, 106037056u64, 106167872u64, 106298944u64, - 106429504u64, 106561472u64, 106691392u64, 106822592u64, 106954304u64, 107085376u64, - 107216576u64, 107346368u64, 107478464u64, 107609792u64, 107739712u64, 107872192u64, - 108003136u64, 108131392u64, 108265408u64, 108396224u64, 108527168u64, 108657344u64, - 108789568u64, 108920384u64, 109049792u64, 109182272u64, 109312576u64, 109444928u64, - 109572928u64, 109706944u64, 109837888u64, 109969088u64, 110099648u64, 110230976u64, - 110362432u64, 110492992u64, 110624704u64, 110755264u64, 110886208u64, 111017408u64, - 111148864u64, 111279296u64, 111410752u64, 111541952u64, 111673024u64, 111803456u64, - 111933632u64, 112066496u64, 112196416u64, 112328512u64, 112457792u64, 112590784u64, - 112715968u64, 112852672u64, 112983616u64, 113114944u64, 113244224u64, 113376448u64, - 113505472u64, 113639104u64, 113770304u64, 113901376u64, 114031552u64, 114163264u64, - 114294592u64, 114425536u64, 114556864u64, 114687424u64, 114818624u64, 114948544u64, - 115080512u64, 115212224u64, 115343296u64, 115473472u64, 115605184u64, 115736128u64, - 115867072u64, 115997248u64, 116128576u64, 116260288u64, 116391488u64, 116522944u64, - 116652992u64, 116784704u64, 116915648u64, 117046208u64, 117178304u64, 117308608u64, - 117440192u64, 117569728u64, 117701824u64, 117833024u64, 117964096u64, 118094656u64, - 118225984u64, 118357312u64, 118489024u64, 118617536u64, 118749632u64, 118882112u64, - 119012416u64, 119144384u64, 119275328u64, 119406016u64, 119537344u64, 119668672u64, - 119798464u64, 119928896u64, 120061376u64, 120192832u64, 120321728u64, 120454336u64, - 120584512u64, 120716608u64, 120848192u64, 120979136u64, 121109056u64, 121241408u64, - 121372352u64, 121502912u64, 121634752u64, 121764416u64, 121895744u64, 122027072u64, - 122157632u64, 122289088u64, 122421184u64, 122550592u64, 122682944u64, 122813888u64, - 122945344u64, 123075776u64, 123207488u64, 123338048u64, 123468736u64, 123600704u64, - 123731264u64, 123861952u64, 123993664u64, 124124608u64, 124256192u64, 124386368u64, - 124518208u64, 124649024u64, 124778048u64, 124911296u64, 125041088u64, 125173696u64, - 125303744u64, 125432896u64, 125566912u64, 125696576u64, 125829056u64, 125958592u64, - 126090304u64, 126221248u64, 126352832u64, 126483776u64, 126615232u64, 126746432u64, - 126876608u64, 127008704u64, 127139392u64, 127270336u64, 127401152u64, 127532224u64, - 127663552u64, 127794752u64, 127925696u64, 128055232u64, 128188096u64, 128319424u64, - 128449856u64, 128581312u64, 128712256u64, 128843584u64, 128973632u64, 129103808u64, - 129236288u64, 129365696u64, 129498944u64, 129629888u64, 129760832u64, 129892288u64, - 130023104u64, 130154048u64, 130283968u64, 130416448u64, 130547008u64, 130678336u64, - 130807616u64, 130939456u64, 131071552u64, 131202112u64, 131331776u64, 131464384u64, - 131594048u64, 131727296u64, 131858368u64, 131987392u64, 132120256u64, 132250816u64, - 132382528u64, 132513728u64, 132644672u64, 132774976u64, 132905792u64, 133038016u64, - 133168832u64, 133299392u64, 133429312u64, 133562048u64, 133692992u64, 133823296u64, - 133954624u64, 134086336u64, 134217152u64, 134348608u64, 134479808u64, 134607296u64, - 134741056u64, 134872384u64, 135002944u64, 135134144u64, 135265472u64, 135396544u64, - 135527872u64, 135659072u64, 135787712u64, 135921472u64, 136052416u64, 136182848u64, - 136313792u64, 136444864u64, 136576448u64, 136707904u64, 136837952u64, 136970048u64, - 137099584u64, 137232064u64, 137363392u64, 137494208u64, 137625536u64, 137755712u64, - 137887424u64, 138018368u64, 138149824u64, 138280256u64, 138411584u64, 138539584u64, - 138672832u64, 138804928u64, 138936128u64, 139066688u64, 139196864u64, 139328704u64, - 139460032u64, 139590208u64, 139721024u64, 139852864u64, 139984576u64, 140115776u64, - 140245696u64, 140376512u64, 140508352u64, 140640064u64, 140769856u64, 140902336u64, - 141032768u64, 141162688u64, 141294016u64, 141426496u64, 141556544u64, 141687488u64, - 141819584u64, 141949888u64, 142080448u64, 142212544u64, 142342336u64, 142474432u64, - 142606144u64, 142736192u64, 142868288u64, 142997824u64, 143129408u64, 143258944u64, - 143392448u64, 143523136u64, 143653696u64, 143785024u64, 143916992u64, 144045632u64, - 144177856u64, 144309184u64, 144440768u64, 144570688u64, 144701888u64, 144832448u64, - 144965056u64, 145096384u64, 145227584u64, 145358656u64, 145489856u64, 145620928u64, - 145751488u64, 145883072u64, 146011456u64, 146144704u64, 146275264u64, 146407232u64, - 146538176u64, 146668736u64, 146800448u64, 146931392u64, 147062336u64, 147193664u64, - 147324224u64, 147455936u64, 147586624u64, 147717056u64, 147848768u64, 147979456u64, - 148110784u64, 148242368u64, 148373312u64, 148503232u64, 148635584u64, 148766144u64, - 148897088u64, 149028416u64, 149159488u64, 149290688u64, 149420224u64, 149551552u64, - 149683136u64, 149814976u64, 149943616u64, 150076352u64, 150208064u64, 150338624u64, - 150470464u64, 150600256u64, 150732224u64, 150862784u64, 150993088u64, 151125952u64, - 151254976u64, 151388096u64, 151519168u64, 151649728u64, 151778752u64, 151911104u64, - 152042944u64, 152174144u64, 152304704u64, 152435648u64, 152567488u64, 152698816u64, - 152828992u64, 152960576u64, 153091648u64, 153222976u64, 153353792u64, 153484096u64, - 153616192u64, 153747008u64, 153878336u64, 154008256u64, 154139968u64, 154270912u64, - 154402624u64, 154533824u64, 154663616u64, 154795712u64, 154926272u64, 155057984u64, - 155188928u64, 155319872u64, 155450816u64, 155580608u64, 155712064u64, 155843392u64, - 155971136u64, 156106688u64, 156237376u64, 156367424u64, 156499264u64, 156630976u64, - 156761536u64, 156892352u64, 157024064u64, 157155008u64, 157284416u64, 157415872u64, - 157545536u64, 157677248u64, 157810496u64, 157938112u64, 158071744u64, 158203328u64, - 158334656u64, 158464832u64, 158596288u64, 158727616u64, 158858048u64, 158988992u64, - 159121216u64, 159252416u64, 159381568u64, 159513152u64, 159645632u64, 159776192u64, - 159906496u64, 160038464u64, 160169536u64, 160300352u64, 160430656u64, 160563008u64, - 160693952u64, 160822208u64, 160956352u64, 161086784u64, 161217344u64, 161349184u64, - 161480512u64, 161611456u64, 161742272u64, 161873216u64, 162002752u64, 162135872u64, - 162266432u64, 162397888u64, 162529216u64, 162660032u64, 162790976u64, 162922048u64, - 163052096u64, 163184576u64, 163314752u64, 163446592u64, 163577408u64, 163707968u64, - 163839296u64, 163969984u64, 164100928u64, 164233024u64, 164364224u64, 164494912u64, - 164625856u64, 164756672u64, 164887616u64, 165019072u64, 165150016u64, 165280064u64, - 165412672u64, 165543104u64, 165674944u64, 165805888u64, 165936832u64, 166067648u64, - 166198336u64, 166330048u64, 166461248u64, 166591552u64, 166722496u64, 166854208u64, - 166985408u64, 167116736u64, 167246656u64, 167378368u64, 167508416u64, 167641024u64, - 167771584u64, 167903168u64, 168034112u64, 168164032u64, 168295744u64, 168427456u64, - 168557632u64, 168688448u64, 168819136u64, 168951616u64, 169082176u64, 169213504u64, - 169344832u64, 169475648u64, 169605952u64, 169738048u64, 169866304u64, 169999552u64, - 170131264u64, 170262464u64, 170393536u64, 170524352u64, 170655424u64, 170782016u64, - 170917696u64, 171048896u64, 171179072u64, 171310784u64, 171439936u64, 171573184u64, - 171702976u64, 171835072u64, 171966272u64, 172097216u64, 172228288u64, 172359232u64, - 172489664u64, 172621376u64, 172747712u64, 172883264u64, 173014208u64, 173144512u64, - 173275072u64, 173407424u64, 173539136u64, 173669696u64, 173800768u64, 173931712u64, - 174063424u64, 174193472u64, 174325696u64, 174455744u64, 174586816u64, 174718912u64, - 174849728u64, 174977728u64, 175109696u64, 175242688u64, 175374272u64, 175504832u64, - 175636288u64, 175765696u64, 175898432u64, 176028992u64, 176159936u64, 176291264u64, - 176422592u64, 176552512u64, 176684864u64, 176815424u64, 176946496u64, 177076544u64, - 177209152u64, 177340096u64, 177470528u64, 177600704u64, 177731648u64, 177864256u64, - 177994816u64, 178126528u64, 178257472u64, 178387648u64, 178518464u64, 178650176u64, - 178781888u64, 178912064u64, 179044288u64, 179174848u64, 179305024u64, 179436736u64, - 179568448u64, 179698496u64, 179830208u64, 179960512u64, 180092608u64, 180223808u64, - 180354752u64, 180485696u64, 180617152u64, 180748096u64, 180877504u64, 181009984u64, - 181139264u64, 181272512u64, 181402688u64, 181532608u64, 181663168u64, 181795136u64, - 181926592u64, 182057536u64, 182190016u64, 182320192u64, 182451904u64, 182582336u64, - 182713792u64, 182843072u64, 182976064u64, 183107264u64, 183237056u64, 183368384u64, - 183494848u64, 183631424u64, 183762752u64, 183893824u64, 184024768u64, 184154816u64, - 184286656u64, 184417984u64, 184548928u64, 184680128u64, 184810816u64, 184941248u64, - 185072704u64, 185203904u64, 185335616u64, 185465408u64, 185596352u64, 185727296u64, - 185859904u64, 185989696u64, 186121664u64, 186252992u64, 186383552u64, 186514112u64, - 186645952u64, 186777152u64, 186907328u64, 187037504u64, 187170112u64, 187301824u64, - 187429184u64, 187562048u64, 187693504u64, 187825472u64, 187957184u64, 188087104u64, - 188218304u64, 188349376u64, 188481344u64, 188609728u64, 188743616u64, 188874304u64, - 189005248u64, 189136448u64, 189265088u64, 189396544u64, 189528128u64, 189660992u64, - 189791936u64, 189923264u64, 190054208u64, 190182848u64, 190315072u64, 190447424u64, - 190577984u64, 190709312u64, 190840768u64, 190971328u64, 191102656u64, 191233472u64, - 191364032u64, 191495872u64, 191626816u64, 191758016u64, 191888192u64, 192020288u64, - 192148928u64, 192282176u64, 192413504u64, 192542528u64, 192674752u64, 192805952u64, - 192937792u64, 193068608u64, 193198912u64, 193330496u64, 193462208u64, 193592384u64, - 193723456u64, 193854272u64, 193985984u64, 194116672u64, 194247232u64, 194379712u64, - 194508352u64, 194641856u64, 194772544u64, 194900672u64, 195035072u64, 195166016u64, - 195296704u64, 195428032u64, 195558592u64, 195690304u64, 195818176u64, 195952576u64, - 196083392u64, 196214336u64, 196345792u64, 196476736u64, 196607552u64, 196739008u64, - 196869952u64, 197000768u64, 197130688u64, 197262784u64, 197394368u64, 197523904u64, - 197656384u64, 197787584u64, 197916608u64, 198049472u64, 198180544u64, 198310208u64, - 198442432u64, 198573632u64, 198705088u64, 198834368u64, 198967232u64, 199097792u64, - 199228352u64, 199360192u64, 199491392u64, 199621696u64, 199751744u64, 199883968u64, - 200014016u64, 200146624u64, 200276672u64, 200408128u64, 200540096u64, 200671168u64, - 200801984u64, 200933312u64, 201062464u64, 201194944u64, 201326144u64, 201457472u64, - 201588544u64, 201719744u64, 201850816u64, 201981632u64, 202111552u64, 202244032u64, - 202374464u64, 202505152u64, 202636352u64, 202767808u64, 202898368u64, 203030336u64, - 203159872u64, 203292608u64, 203423296u64, 203553472u64, 203685824u64, 203816896u64, - 203947712u64, 204078272u64, 204208192u64, 204341056u64, 204472256u64, 204603328u64, - 204733888u64, 204864448u64, 204996544u64, 205125568u64, 205258304u64, 205388864u64, - 205517632u64, 205650112u64, 205782208u64, 205913536u64, 206044736u64, 206176192u64, - 206307008u64, 206434496u64, 206569024u64, 206700224u64, 206831168u64, 206961856u64, - 207093056u64, 207223616u64, 207355328u64, 207486784u64, 207616832u64, 207749056u64, - 207879104u64, 208010048u64, 208141888u64, 208273216u64, 208404032u64, 208534336u64, - 208666048u64, 208796864u64, 208927424u64, 209059264u64, 209189824u64, 209321792u64, - 209451584u64, 209582656u64, 209715136u64, 209845568u64, 209976896u64, 210106432u64, - 210239296u64, 210370112u64, 210501568u64, 210630976u64, 210763712u64, 210894272u64, - 211024832u64, 211156672u64, 211287616u64, 211418176u64, 211549376u64, 211679296u64, - 211812032u64, 211942592u64, 212074432u64, 212204864u64, 212334016u64, 212467648u64, - 212597824u64, 212727616u64, 212860352u64, 212991424u64, 213120832u64, 213253952u64, - 213385024u64, 213515584u64, 213645632u64, 213777728u64, 213909184u64, 214040128u64, - 214170688u64, 214302656u64, 214433728u64, 214564544u64, 214695232u64, 214826048u64, - 214956992u64, 215089088u64, 215219776u64, 215350592u64, 215482304u64, 215613248u64, - 215743552u64, 215874752u64, 216005312u64, 216137024u64, 216267328u64, 216399296u64, - 216530752u64, 216661696u64, 216790592u64, 216923968u64, 217054528u64, 217183168u64, - 217316672u64, 217448128u64, 217579072u64, 217709504u64, 217838912u64, 217972672u64, - 218102848u64, 218233024u64, 218364736u64, 218496832u64, 218627776u64, 218759104u64, - 218888896u64, 219021248u64, 219151936u64, 219281728u64, 219413056u64, 219545024u64, - 219675968u64, 219807296u64, 219938624u64, 220069312u64, 220200128u64, 220331456u64, - 220461632u64, 220592704u64, 220725184u64, 220855744u64, 220987072u64, 221117888u64, - 221249216u64, 221378368u64, 221510336u64, 221642048u64, 221772736u64, 221904832u64, - 222031808u64, 222166976u64, 222297536u64, 222428992u64, 222559936u64, 222690368u64, - 222820672u64, 222953152u64, 223083968u64, 223213376u64, 223345984u64, 223476928u64, - 223608512u64, 223738688u64, 223869376u64, 224001472u64, 224132672u64, 224262848u64, - 224394944u64, 224524864u64, 224657344u64, 224788288u64, 224919488u64, 225050432u64, - 225181504u64, 225312704u64, 225443776u64, 225574592u64, 225704768u64, 225834176u64, - 225966784u64, 226097216u64, 226229824u64, 226360384u64, 226491712u64, 226623424u64, - 226754368u64, 226885312u64, 227015104u64, 227147456u64, 227278528u64, 227409472u64, - 227539904u64, 227669696u64, 227802944u64, 227932352u64, 228065216u64, 228196288u64, - 228326464u64, 228457792u64, 228588736u64, 228720064u64, 228850112u64, 228981056u64, - 229113152u64, 229243328u64, 229375936u64, 229505344u64, 229636928u64, 229769152u64, - 229894976u64, 230030272u64, 230162368u64, 230292416u64, 230424512u64, 230553152u64, - 230684864u64, 230816704u64, 230948416u64, 231079616u64, 231210944u64, 231342016u64, - 231472448u64, 231603776u64, 231733952u64, 231866176u64, 231996736u64, 232127296u64, - 232259392u64, 232388672u64, 232521664u64, 232652608u64, 232782272u64, 232914496u64, - 233043904u64, 233175616u64, 233306816u64, 233438528u64, 233569984u64, 233699776u64, - 233830592u64, 233962688u64, 234092224u64, 234221888u64, 234353984u64, 234485312u64, - 234618304u64, 234749888u64, 234880832u64, 235011776u64, 235142464u64, 235274048u64, - 235403456u64, 235535936u64, 235667392u64, 235797568u64, 235928768u64, 236057152u64, - 236190272u64, 236322752u64, 236453312u64, 236583616u64, 236715712u64, 236846528u64, - 236976448u64, 237108544u64, 237239104u64, 237371072u64, 237501632u64, 237630784u64, - 237764416u64, 237895232u64, 238026688u64, 238157632u64, 238286912u64, 238419392u64, - 238548032u64, 238681024u64, 238812608u64, 238941632u64, 239075008u64, 239206336u64, - 239335232u64, 239466944u64, 239599168u64, 239730496u64, 239861312u64, 239992384u64, - 240122816u64, 240254656u64, 240385856u64, 240516928u64, 240647872u64, 240779072u64, - 240909632u64, 241040704u64, 241171904u64, 241302848u64, 241433408u64, 241565248u64, - 241696192u64, 241825984u64, 241958848u64, 242088256u64, 242220224u64, 242352064u64, - 242481856u64, 242611648u64, 242744896u64, 242876224u64, 243005632u64, 243138496u64, - 243268672u64, 243400384u64, 243531712u64, 243662656u64, 243793856u64, 243924544u64, - 244054592u64, 244187072u64, 244316608u64, 244448704u64, 244580032u64, 244710976u64, - 244841536u64, 244972864u64, 245104448u64, 245233984u64, 245365312u64, 245497792u64, - 245628736u64, 245759936u64, 245889856u64, 246021056u64, 246152512u64, 246284224u64, - 246415168u64, 246545344u64, 246675904u64, 246808384u64, 246939584u64, 247070144u64, - 247199552u64, 247331648u64, 247463872u64, 247593536u64, 247726016u64, 247857088u64, - 247987648u64, 248116928u64, 248249536u64, 248380736u64, 248512064u64, 248643008u64, - 248773312u64, 248901056u64, 249036608u64, 249167552u64, 249298624u64, 249429184u64, - 249560512u64, 249692096u64, 249822784u64, 249954112u64, 250085312u64, 250215488u64, - 250345792u64, 250478528u64, 250608704u64, 250739264u64, 250870976u64, 251002816u64, - 251133632u64, 251263552u64, 251395136u64, 251523904u64, 251657792u64, 251789248u64, - 251919424u64, 252051392u64, 252182464u64, 252313408u64, 252444224u64, 252575552u64, - 252706624u64, 252836032u64, 252968512u64, 253099712u64, 253227584u64, 253361728u64, - 253493056u64, 253623488u64, 253754432u64, 253885504u64, 254017216u64, 254148032u64, - 254279488u64, 254410432u64, 254541376u64, 254672576u64, 254803264u64, 254933824u64, - 255065792u64, 255196736u64, 255326528u64, 255458752u64, 255589952u64, 255721408u64, - 255851072u64, 255983296u64, 256114624u64, 256244416u64, 256374208u64, 256507712u64, - 256636096u64, 256768832u64, 256900544u64, 257031616u64, 257162176u64, 257294272u64, - 257424448u64, 257555776u64, 257686976u64, 257818432u64, 257949632u64, 258079552u64, - 258211136u64, 258342464u64, 258473408u64, 258603712u64, 258734656u64, 258867008u64, - 258996544u64, 259127744u64, 259260224u64, 259391296u64, 259522112u64, 259651904u64, - 259784384u64, 259915328u64, 260045888u64, 260175424u64, 260308544u64, 260438336u64, - 260570944u64, 260700992u64, 260832448u64, 260963776u64, 261092672u64, 261226304u64, - 261356864u64, 261487936u64, 261619648u64, 261750592u64, 261879872u64, 262011968u64, - 262143424u64, 262274752u64, 262404416u64, 262537024u64, 262667968u64, 262799296u64, - 262928704u64, 263061184u64, 263191744u64, 263322944u64, 263454656u64, 263585216u64, - 263716672u64, 263847872u64, 263978944u64, 264108608u64, 264241088u64, 264371648u64, - 264501184u64, 264632768u64, 264764096u64, 264895936u64, 265024576u64, 265158464u64, - 265287488u64, 265418432u64, 265550528u64, 265681216u64, 265813312u64, 265943488u64, - 266075968u64, 266206144u64, 266337728u64, 266468032u64, 266600384u64, 266731072u64, - 266862272u64, 266993344u64, 267124288u64, 267255616u64, 267386432u64, 267516992u64, - 267648704u64, 267777728u64, 267910592u64, 268040512u64, 268172096u64, 268302784u64, - 268435264u64, 268566208u64, 268696256u64, 268828096u64, 268959296u64, 269090368u64, - 269221312u64, 269352256u64, 269482688u64, 269614784u64, 269745856u64, 269876416u64, - 270007616u64, 270139328u64, 270270272u64, 270401216u64, 270531904u64, 270663616u64, - 270791744u64, 270924736u64, 271056832u64, 271186112u64, 271317184u64, 271449536u64, - 271580992u64, 271711936u64, 271843136u64, 271973056u64, 272105408u64, 272236352u64, - 272367296u64, 272498368u64, 272629568u64, 272759488u64, 272891456u64, 273022784u64, - 273153856u64, 273284672u64, 273415616u64, 273547072u64, 273677632u64, 273808448u64, - 273937088u64, 274071488u64, 274200896u64, 274332992u64, 274463296u64, 274595392u64, - 274726208u64, 274857536u64, 274988992u64, 275118656u64, 275250496u64, 275382208u64, - 275513024u64, 275643968u64, 275775296u64, 275906368u64, 276037184u64, 276167872u64, - 276297664u64, 276429376u64, 276560576u64, 276692672u64, 276822976u64, 276955072u64, - 277085632u64, 277216832u64, 277347008u64, 277478848u64, 277609664u64, 277740992u64, - 277868608u64, 278002624u64, 278134336u64, 278265536u64, 278395328u64, 278526784u64, - 278657728u64, 278789824u64, 278921152u64, 279052096u64, 279182912u64, 279313088u64, - 279443776u64, 279576256u64, 279706048u64, 279838528u64, 279969728u64, 280099648u64, - 280230976u64, 280361408u64, 280493632u64, 280622528u64, 280755392u64, 280887104u64, - 281018176u64, 281147968u64, 281278912u64, 281411392u64, 281542592u64, 281673152u64, - 281803712u64, 281935552u64, 282066496u64, 282197312u64, 282329024u64, 282458816u64, - 282590272u64, 282720832u64, 282853184u64, 282983744u64, 283115072u64, 283246144u64, - 283377344u64, 283508416u64, 283639744u64, 283770304u64, 283901504u64, 284032576u64, - 284163136u64, 284294848u64, 284426176u64, 284556992u64, 284687296u64, 284819264u64, - 284950208u64, 285081536u64 -]; - From bcc4ca48ab11da19627673b7d1fbb7fb1dff33b6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 21 Feb 2016 15:19:08 +0300 Subject: [PATCH 142/753] to new namespace --- util/src/kvdb.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index fa74553fb..921e8b3c4 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -69,7 +69,7 @@ pub struct Database { impl Database { /// Open database with default settings. pub fn open_default(path: &str) -> Result { - Database::open(&DatabaseConfig { prefix_size: None }, path) + Database::open(&DatabaseConfig { prefix_size: None }, path) } /// Open database file. Creates if it does not exist. @@ -120,7 +120,7 @@ impl Database { pub fn write(&self, tr: DBTransaction) -> Result<(), String> { self.db.write(tr.batch) } - + /// Get value by key. pub fn get(&self, key: &[u8]) -> Result, String> { self.db.get(key) @@ -152,7 +152,7 @@ impl Database { mod tests { use hash::*; use super::*; - use tests::helpers::RandomTempPath; + use devtools::*; use std::str::FromStr; use std::ops::Deref; @@ -185,7 +185,7 @@ mod tests { db.write(transaction).unwrap(); assert!(db.get(&key1).unwrap().is_none()); assert_eq!(db.get(&key3).unwrap().unwrap().deref(), b"elephant"); - + if config.prefix_size.is_some() { assert_eq!(db.get_by_prefix(&key3).unwrap().deref(), b"elephant"); assert_eq!(db.get_by_prefix(&key2).unwrap().deref(), b"dog"); From fe84eb4ff65b843cf0f56e1d4b038574ce144e53 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 21 Feb 2016 13:58:01 +0100 Subject: [PATCH 143/753] Fix locking --- util/src/network/host.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index feddf1952..70915bee3 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -777,7 +777,8 @@ impl IoHandler> for Host where Messa FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), DISCOVERY => { - if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().readable() { + let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().readable() }; + if let Some(node_changes) = node_changes { self.update_nodes(io, node_changes); } io.update_registration(DISCOVERY).expect("Error updating discovery registration"); @@ -809,7 +810,8 @@ impl IoHandler> for Host where Messa io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, DISCOVERY_ROUND => { - if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().round() { + let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().round() }; + if let Some(node_changes) = node_changes { self.update_nodes(io, node_changes); } io.update_registration(DISCOVERY).expect("Error updating discovery registration"); From 8b50fa658fa22d3c7ac71aba36fb5b96c73dd5ce Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 21 Feb 2016 16:32:11 +0100 Subject: [PATCH 144/753] Fix typo in deps script. --- install-deps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-deps.sh b/install-deps.sh index 214b6748c..f5e1e44cf 100755 --- a/install-deps.sh +++ b/install-deps.sh @@ -425,7 +425,7 @@ function run_installer() depFound=$((depFound+1)) check "multirust" isMultirust=true - if [[ $(multirust show-default 2>/dev/null | grep beta | wc -l) == 4 ]]; then + if [[ $(multirust show-default 2>/dev/null | grep beta | wc -l) == 3 ]]; then depFound=$((depFound+1)) check "rust beta" isMultirustBeta=true From 91276ad82e702dca8f3183511fcfed7703c70a5c Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 21 Feb 2016 16:52:25 +0100 Subject: [PATCH 145/753] Added comments --- util/src/network/connection.rs | 1 + util/src/network/handshake.rs | 1 + util/src/network/session.rs | 5 +++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 0135fc333..a7396ff33 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -175,6 +175,7 @@ impl Connection { self.socket.peer_addr() } + /// Clone this connection. Clears the receiving buffer of the returned connection. pub fn try_clone(&self) -> io::Result { Ok(Connection { token: self.token, diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index a50dd6ba2..087de63b3 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -176,6 +176,7 @@ impl Handshake { Ok(()) } + /// Update socket registration with the event loop. pub fn update_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { if !self.expired() { try!(self.connection.update_socket(reg, event_loop)); diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 6be1dbfe4..edf929a9a 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -111,7 +111,8 @@ const PACKET_USER: u8 = 0x10; const PACKET_LAST: u8 = 0x7f; impl Session { - /// Create a new session out of comepleted handshake. + /// Create a new session out of comepleted handshake. This clones the handshake connection object + /// and leaves the handhsake in limbo to be deregistered from the event loop. pub fn new(h: &mut Handshake, host: &HostInfo) -> Result { let id = h.id.clone(); let connection = try!(EncryptedConnection::new(h)); @@ -189,7 +190,7 @@ impl Session { } /// Register the session socket with the event loop - pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { if self.expired() { return Ok(()); } From 67cd29f4e14c7877c1af0341025322e3e047a0ca Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 21 Feb 2016 16:58:56 +0100 Subject: [PATCH 146/753] Whitespaces --- util/src/kvdb.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index 921e8b3c4..23784c200 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -31,12 +31,12 @@ impl DBTransaction { } /// Insert a key-value pair in the transaction. Any existing value value will be overwritten upon write. - pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { + pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { self.batch.put(key, value) } /// Delete value by key. - pub fn delete(&self, key: &[u8]) -> Result<(), String> { + pub fn delete(&self, key: &[u8]) -> Result<(), String> { self.batch.delete(key) } } @@ -49,14 +49,14 @@ pub struct DatabaseConfig { /// Database iterator pub struct DatabaseIterator<'a> { - iter: DBIterator<'a>, + iter: DBIterator<'a>, } impl<'a> Iterator for DatabaseIterator<'a> { - type Item = (Box<[u8]>, Box<[u8]>); + type Item = (Box<[u8]>, Box<[u8]>); #[allow(type_complexity)] - fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> { + fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> { self.iter.next() } } @@ -94,7 +94,8 @@ impl Database { opts.set_max_background_compactions(4); opts.set_max_background_flushes(4); opts.set_filter_deletes(false); - opts.set_disable_auto_compactions(false);*/ + opts.set_disable_auto_compactions(false); + */ if let Some(size) = config.prefix_size { let mut block_opts = BlockBasedOptions::new(); @@ -107,27 +108,27 @@ impl Database { } /// Insert a key-value pair in the transaction. Any existing value value will be overwritten. - pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { + pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { self.db.put(key, value) } /// Delete value by key. - pub fn delete(&self, key: &[u8]) -> Result<(), String> { + pub fn delete(&self, key: &[u8]) -> Result<(), String> { self.db.delete(key) } /// Commit transaction to database. - pub fn write(&self, tr: DBTransaction) -> Result<(), String> { + pub fn write(&self, tr: DBTransaction) -> Result<(), String> { self.db.write(tr.batch) } /// Get value by key. - pub fn get(&self, key: &[u8]) -> Result, String> { + pub fn get(&self, key: &[u8]) -> Result, String> { self.db.get(key) } /// Get value by partial key. Prefix size should match configured prefix size. - pub fn get_by_prefix(&self, prefix: &[u8]) -> Option> { + pub fn get_by_prefix(&self, prefix: &[u8]) -> Option> { let mut iter = self.db.iterator(IteratorMode::From(prefix, Direction::forward)); match iter.next() { // TODO: use prefix_same_as_start read option (not availabele in C API currently) @@ -147,7 +148,6 @@ impl Database { } } - #[cfg(test)] mod tests { use hash::*; From 63bbd0ccd8b592bc8260ed41e8d558848ebdc088 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 21 Feb 2016 20:00:45 +0100 Subject: [PATCH 147/753] Use proper version string. --- Cargo.lock | 2 ++ parity/main.rs | 7 +++---- rpc/Cargo.toml | 1 + rpc/src/lib.rs | 1 - rpc/src/v1/impls/web3.rs | 6 ++++-- util/Cargo.toml | 1 + util/src/lib.rs | 1 + util/src/misc.rs | 7 +++++++ util/src/network/host.rs | 4 ++-- 9 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 259a0c4d8..acdb241ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,6 +204,7 @@ dependencies = [ "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -234,6 +235,7 @@ dependencies = [ "rocksdb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/parity/main.rs b/parity/main.rs index 58d3a6f4c..f4b7880ab 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -29,7 +29,6 @@ extern crate log as rlog; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; -extern crate target_info; extern crate daemonize; #[cfg(feature = "rpc")] @@ -51,7 +50,6 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use docopt::Docopt; -use target_info::Target; use daemonize::Daemonize; const USAGE: &'static str = " @@ -146,14 +144,15 @@ fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) { fn print_version() { println!("\ -Parity version {} ({}-{}-{}) +Parity + version {} Copyright 2015, 2016 Ethcore (UK) Limited License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf.\ -", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()); +", version()); } fn die_with_message(msg: &str) -> ! { diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 0b7c17383..bce5b609c 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -20,6 +20,7 @@ clippy = { version = "0.0.42", optional = true } target_info = "0.1.0" rustc-serialize = "0.3" serde_macros = { version = "0.6.13", optional = true } +rustc_version = "0.1.0" [build-dependencies] serde_codegen = { version = "0.6.13", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index c9542ade7..d7b5bdc3b 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,7 +20,6 @@ #![cfg_attr(nightly, plugin(serde_macros, clippy))] extern crate rustc_serialize; -extern crate target_info; extern crate serde; extern crate serde_json; extern crate jsonrpc_core; diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index f10150a30..0a237d56b 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . //! Web3 rpc implementation. -use target_info::Target; use jsonrpc_core::*; +use util::version; use v1::traits::Web3; /// Web3 rpc implementation. @@ -30,7 +30,9 @@ impl Web3Client { impl Web3 for Web3Client { fn client_version(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::String(format!("Parity/-/{}/{}-{}-{}/rust1.8-nightly", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()))), + Params::None => { + Ok(Value::String(version())), + } _ => Err(Error::invalid_params()) } } diff --git a/util/Cargo.toml b/util/Cargo.toml index 5d7fa697f..29d820760 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -29,6 +29,7 @@ serde = "0.6.7" clippy = { version = "0.0.42", optional = true } json-tests = { path = "json-tests" } target_info = "0.1.0" +rustc_version = "0.1.0" igd = "0.4.2" ethcore-devtools = { path = "../devtools" } libc = "0.2.7" diff --git a/util/src/lib.rs b/util/src/lib.rs index 9527341ad..b91e2d65b 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -108,6 +108,7 @@ extern crate log as rlog; extern crate igd; extern crate ethcore_devtools as devtools; extern crate libc; +extern crate rustc_version; pub mod standard; #[macro_use] diff --git a/util/src/misc.rs b/util/src/misc.rs index ae3dbc5bf..fdbaa0b49 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -18,6 +18,8 @@ use std::fs::File; use common::*; +use target_info::Target; +use rustc_version; #[derive(Debug,Clone,PartialEq,Eq)] /// Diff type for specifying a change (or not). @@ -62,3 +64,8 @@ pub fn contents(name: &str) -> Result { try!(file.read_to_end(&mut ret)); Ok(ret) } + +/// Get the standard version string for this software. +pub fn version() -> String { + format!("Parity/-/{}/{}-{}-{}/{}", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os(), rustc_version::version()) +} \ No newline at end of file diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 326cd2715..fb3150ad3 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -26,8 +26,8 @@ use std::io::{Read, Write}; use std::fs; use mio::*; use mio::tcp::*; -use target_info::Target; use hash::*; +use misc::version; use crypto::*; use sha3::Hashable; use rlp::*; @@ -360,7 +360,7 @@ impl Host where Message: Send + Sync + Clone { config: config, nonce: H256::random(), protocol_version: PROTOCOL_VERSION, - client_version: format!("Parity/{}/{}-{}-{}", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()), + client_version: version(), listen_port: 0, capabilities: Vec::new(), }), From 6fa2284c6889ee3815d18481043c897a928eb4ab Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 21 Feb 2016 20:03:01 +0100 Subject: [PATCH 148/753] Remove unneeded deps. --- Cargo.lock | 3 --- Cargo.toml | 1 - rpc/Cargo.toml | 2 -- 3 files changed, 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acdb241ac..16b41d0e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,7 +15,6 @@ dependencies = [ "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -204,12 +203,10 @@ dependencies = [ "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3cb158df7..7fdfc2bee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ ethcore = { path = "ethcore" } ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } -target_info = "0.1" daemonize = "0.2" ethcore-devtools = { path = "devtools" } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index bce5b609c..be06316a4 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -17,10 +17,8 @@ ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } clippy = { version = "0.0.42", optional = true } -target_info = "0.1.0" rustc-serialize = "0.3" serde_macros = { version = "0.6.13", optional = true } -rustc_version = "0.1.0" [build-dependencies] serde_codegen = { version = "0.6.13", optional = true } From ea187253a23d7394720d3b071d5888d30f2227d0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 21 Feb 2016 21:14:09 +0100 Subject: [PATCH 149/753] Include git commit date & hash. --- Cargo.lock | 21 +++++++++++++++------ util/Cargo.toml | 6 +++++- util/build.rs | 6 ++++++ util/src/lib.rs | 2 +- util/src/misc.rs | 5 +++-- 5 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 util/build.rs diff --git a/Cargo.lock b/Cargo.lock index 16b41d0e8..8bf4a3764 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,11 @@ name = "bitflags" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blastfig" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bytes" version = "0.3.0" @@ -236,9 +241,9 @@ dependencies = [ "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -687,11 +692,6 @@ dependencies = [ "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "target_info" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "term" version = "0.2.14" @@ -788,6 +788,15 @@ dependencies = [ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vergen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.5" diff --git a/util/Cargo.toml b/util/Cargo.toml index 29d820760..aae6a3d85 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -5,6 +5,7 @@ license = "GPL-3.0" name = "ethcore-util" version = "0.9.99" authors = ["Ethcore "] +build = "build.rs" [dependencies] log = "0.3" @@ -28,12 +29,15 @@ sha3 = { path = "sha3" } serde = "0.6.7" clippy = { version = "0.0.42", optional = true } json-tests = { path = "json-tests" } -target_info = "0.1.0" rustc_version = "0.1.0" igd = "0.4.2" ethcore-devtools = { path = "../devtools" } libc = "0.2.7" +vergen = "*" [features] default = [] dev = ["clippy"] + +[build-dependencies] +vergen = "*" diff --git a/util/build.rs b/util/build.rs new file mode 100644 index 000000000..32ee30472 --- /dev/null +++ b/util/build.rs @@ -0,0 +1,6 @@ +extern crate vergen; +use vergen::*; + +fn main() { + vergen(OutputFns::all()).unwrap(); +} \ No newline at end of file diff --git a/util/src/lib.rs b/util/src/lib.rs index b91e2d65b..07593e5eb 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -82,7 +82,6 @@ //! cargo build --release //! ``` -extern crate target_info; extern crate slab; extern crate rustc_serialize; extern crate mio; @@ -109,6 +108,7 @@ extern crate igd; extern crate ethcore_devtools as devtools; extern crate libc; extern crate rustc_version; +extern crate vergen; pub mod standard; #[macro_use] diff --git a/util/src/misc.rs b/util/src/misc.rs index fdbaa0b49..075da476d 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -18,9 +18,10 @@ use std::fs::File; use common::*; -use target_info::Target; use rustc_version; +include!(concat!(env!("OUT_DIR"), "/version.rs")); + #[derive(Debug,Clone,PartialEq,Eq)] /// Diff type for specifying a change (or not). pub enum Diff where T: Eq { @@ -67,5 +68,5 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { - format!("Parity/-/{}/{}-{}-{}/{}", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os(), rustc_version::version()) + format!("Parity/{}/{}-{}/{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date(), target(), rustc_version::version()) } \ No newline at end of file From 0c832853b6624fd9df0e36cee94ace83c48d23a9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 21 Feb 2016 21:22:11 +0100 Subject: [PATCH 150/753] Avoid the dep = "*" --- util/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/Cargo.toml b/util/Cargo.toml index aae6a3d85..da4f8e34e 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -33,7 +33,7 @@ rustc_version = "0.1.0" igd = "0.4.2" ethcore-devtools = { path = "../devtools" } libc = "0.2.7" -vergen = "*" +vergen = "0.1" [features] default = [] From 5b05cbb128bc63dd33c6a2a0a6a33f4b2529c2b8 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 21 Feb 2016 23:23:46 +0300 Subject: [PATCH 151/753] extended keys with accont meta --- ethtools/Cargo.toml | 10 ++++ ethtools/README.md | 1 + ...--3f49624084b67849c7b4e805c5988c21a430f9d9 | 1 + ...--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf | 1 + ethtools/src/geth_keys.rs | 57 +++++++++++++++++++ ethtools/src/lib.rs | 21 +++++++ util/src/hash.rs | 5 +- util/src/keys/directory.rs | 13 ++++- util/src/keys/store.rs | 12 +++- 9 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 ethtools/Cargo.toml create mode 100644 ethtools/README.md create mode 100644 ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 create mode 100644 ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf create mode 100644 ethtools/src/geth_keys.rs create mode 100644 ethtools/src/lib.rs diff --git a/ethtools/Cargo.toml b/ethtools/Cargo.toml new file mode 100644 index 000000000..5529c1d33 --- /dev/null +++ b/ethtools/Cargo.toml @@ -0,0 +1,10 @@ +[package] +description = "Ethcore Ethereum tools" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "ethtools" +version = "0.9.99" +authors = ["Ethcore "] + +[dependencies] +ethcore-util = { path = "../util" } diff --git a/ethtools/README.md b/ethtools/README.md new file mode 100644 index 000000000..f3e852ff5 --- /dev/null +++ b/ethtools/README.md @@ -0,0 +1 @@ +# ethtools diff --git a/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 b/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 new file mode 100644 index 000000000..a62d3056c --- /dev/null +++ b/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 @@ -0,0 +1 @@ +{"address":"3f49624084b67849c7b4e805c5988c21a430f9d9","Crypto":{"cipher":"aes-128-ctr","ciphertext":"9f27e3dd4fc73e7103ed61e5493662189a3eb52223ae49e3d1deacc04c889eae","cipherparams":{"iv":"457494bf05f2618c397dc74dbb5181c0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"db14edb18c41ee7f5ec4397df89c3a2ae4d0af60884c52bb54ce490574f8df33"},"mac":"572d24532438d31fdf513c744a3ff26c933ffda5744ee42bc71661cbe3f2112e"},"id":"62a0ad73-556d-496a-8e1c-0783d30d3ace","version":3} \ No newline at end of file diff --git a/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf b/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf new file mode 100644 index 000000000..b6caa1c47 --- /dev/null +++ b/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf @@ -0,0 +1 @@ +{"address":"5ba4dcf897e97c2bdf8315b9ef26c13c085988cf","Crypto":{"cipher":"aes-128-ctr","ciphertext":"d4a08ec930163778273920f6ad1d49b71836337be6fd9863993ac700a612fddd","cipherparams":{"iv":"89ce5ec129fc27cd5bcbeb8c92bdad50"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"612ab108dc37e69ee8af37a7b24bf7f2234086d7bbf945bacdeccce331f7f84a"},"mac":"4152caa7444e06784223d735cea80cd2690b4c587ad8db3d5529442227b25695"},"id":"35086353-fb12-4029-b56b-033cd61ce35b","version":3} \ No newline at end of file diff --git a/ethtools/src/geth_keys.rs b/ethtools/src/geth_keys.rs new file mode 100644 index 000000000..58dc2a0b1 --- /dev/null +++ b/ethtools/src/geth_keys.rs @@ -0,0 +1,57 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Geth keys import/export tool + +use util::hash::*; +use std::path::Path; +use std::result::*; +use std::fs; +use std::str::FromStr; + +/// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)` +pub fn enumerate_geth_keys(path: &Path) -> Result, ::std::io::Error> { + let mut entries = Vec::new(); + for entry in try!(fs::read_dir(path)) { + let entry = try!(entry); + if !try!(fs::metadata(entry.path())).is_dir() { + match entry.file_name().to_str() { + Some(name) => { + let parts: Vec<&str> = name.split("--").collect(); + if parts.len() != 3 { continue; } + match Address::from_str(parts[2]) { + Ok(account_id) => { entries.push((account_id, name.to_owned())); } + Err(e) => { panic!("error: {:?}", e); } + } + }, + None => { continue; } + }; + } + } + Ok(entries) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::Path; + + #[test] + fn can_enumerate() { + let keys = enumerate_geth_keys(Path::new("res/geth_keystore")).unwrap(); + assert_eq!(2, keys.len()); + } +} diff --git a/ethtools/src/lib.rs b/ethtools/src/lib.rs new file mode 100644 index 000000000..41dd69cf9 --- /dev/null +++ b/ethtools/src/lib.rs @@ -0,0 +1,21 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Ethereum Tools Library + +extern crate ethcore_util as util; + +pub mod geth_keys; diff --git a/util/src/hash.rs b/util/src/hash.rs index 71c690ef6..a6e8f7950 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -235,7 +235,7 @@ macro_rules! impl_hash { } impl serde::Serialize for $from { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { let mut hex = "0x".to_owned(); hex.push_str(self.to_hex().as_ref()); @@ -250,7 +250,7 @@ macro_rules! impl_hash { impl serde::de::Visitor for HashVisitor { type Value = $from; - + fn visit_str(&mut self, value: &str) -> Result where E: serde::Error { // 0x + len if value.len() != 2 + $size * 2 { @@ -719,4 +719,3 @@ mod tests { assert_eq!(r, u); } } - diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index bc875db3f..298f67b99 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -333,7 +333,9 @@ pub struct KeyFileContent { /// Holds cypher and decrypt function settings. pub crypto: KeyFileCrypto, /// The identifier. - pub id: Uuid + pub id: Uuid, + /// Account (if present) + pub account: Option
, } #[derive(Debug)] @@ -374,7 +376,8 @@ impl KeyFileContent { KeyFileContent { id: new_uuid(), version: KeyFileVersion::V3(3), - crypto: crypto + crypto: crypto, + account: None } } @@ -407,6 +410,9 @@ impl KeyFileContent { Ok(id) => id }; + let account = as_object.get("account").and_then(|json| json.as_string()).and_then( + |account_text| match Address::from_str(account_text) { Ok(account) => Some(account), Err(_) => None }); + let crypto = match as_object.get("crypto") { None => { return Err(KeyFileParseError::NoCryptoSection); } Some(crypto_json) => match KeyFileCrypto::from_json(crypto_json) { @@ -418,7 +424,8 @@ impl KeyFileContent { Ok(KeyFileContent { version: version, id: id.clone(), - crypto: crypto + crypto: crypto, + account: account }) } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index ae44d567a..100f3d30c 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -63,12 +63,22 @@ impl SecretStore { /// new instance of Secret Store pub fn new() -> SecretStore { let mut path = ::std::env::home_dir().expect("Failed to get home dir"); - path.push(".keys"); + path.push("keystore"); SecretStore { directory: KeyDirectory::new(&path) } } + pub fn accounts(&self) -> Result, ::std::io::Error> { + let accounts = try!(self.directory.list()).iter().map(|key_id| self.directory.get(key_id)) + .filter(|key| key.is_some()) + .map(|key| { let some_key = key.unwrap(); (some_key.account, some_key.id) }) + .filter(|&(ref account, _)| account.is_some()) + .map(|(account, id)| (account.unwrap(), id)) + .collect::>(); + Ok(accounts) + } + #[cfg(test)] fn new_test(path: &::devtools::RandomTempPath) -> SecretStore { SecretStore { From 8bc0b7c77c79ee5ba1868e678c502ba0aa026925 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 21 Feb 2016 23:44:12 +0300 Subject: [PATCH 152/753] import pub --- util/src/keys/store.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 100f3d30c..284c78b2c 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -69,6 +69,7 @@ impl SecretStore { } } + /// Lists all accounts and corresponding key ids pub fn accounts(&self) -> Result, ::std::io::Error> { let accounts = try!(self.directory.list()).iter().map(|key_id| self.directory.get(key_id)) .filter(|key| key.is_some()) @@ -79,6 +80,21 @@ impl SecretStore { Ok(accounts) } + /// Resolves key_id by account address + pub fn account(&self, account: &Address) -> Option { + let mut accounts = match self.accounts() { + Ok(accounts) => accounts, + Err(e) => { warn!(target: "sstore", "Failed to load accounts: {}", e); return None; } + }; + accounts.retain(|&(ref store_account, _)| account == store_account); + accounts.first().and_then(|&(_, ref key_id)| Some(key_id.clone())) + } + + pub fn import_key(&mut self, key_file: KeyFileContent) -> Result<(), ::std::io::Error> { + try!(self.directory.save(key_file)); + Ok(()) + } + #[cfg(test)] fn new_test(path: &::devtools::RandomTempPath) -> SecretStore { SecretStore { From fbee46d69d56580eaebd3d074bfcc849fd8c9803 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 21 Feb 2016 21:45:56 +0100 Subject: [PATCH 153/753] Fix netstats. --- util/src/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/misc.rs b/util/src/misc.rs index 075da476d..22a2bb673 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -68,5 +68,5 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { - format!("Parity/{}/{}-{}/{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date(), target(), rustc_version::version()) + format!("Parity//{}/{}-{}/{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date(), target(), rustc_version::version()) } \ No newline at end of file From 8db8e5b5f81bd750cd56bd28614e3ce7227de9c0 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 22 Feb 2016 08:46:47 +0100 Subject: [PATCH 154/753] unit tests for reset chain head --- ethcore/src/chainfilter/chainfilter.rs | 2 +- ethcore/src/chainfilter/tests.rs | 64 ++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs index 4f7f30928..6b30066f7 100644 --- a/ethcore/src/chainfilter/chainfilter.rs +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -146,7 +146,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource } // reset the rest of blooms - for reset_number in block_number + blooms.len()..old_highest_block { + for reset_number in block_number + blooms.len()..(old_highest_block + 1) { result.insert(self.indexer.bloom_index(reset_number, 0), H2048::new()); } diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs index 2eb6275ea..2baa93e55 100644 --- a/ethcore/src/chainfilter/tests.rs +++ b/ethcore/src/chainfilter/tests.rs @@ -99,6 +99,68 @@ fn test_topic_basic_search() { } } +#[test] +fn test_reset_chain_head_simple() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + let topic_0 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba").unwrap(); + let topic_1 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbb").unwrap(); + let topic_2 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbc").unwrap(); + let topic_3 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbd").unwrap(); + let topic_4 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbe").unwrap(); + let topic_5 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbf").unwrap(); + + let modified_blooms_0 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 14; + filter.add_bloom(&to_bloom(&topic_0), block_number) + }; + + cache.insert_blooms(modified_blooms_0); + + let modified_blooms_1 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 15; + filter.add_bloom(&to_bloom(&topic_1), block_number) + }; + + cache.insert_blooms(modified_blooms_1); + + let modified_blooms_2 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 16; + filter.add_bloom(&to_bloom(&topic_2), block_number) + }; + + cache.insert_blooms(modified_blooms_2); + + let modified_blooms_3 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 17; + filter.add_bloom(&to_bloom(&topic_3), block_number) + }; + + cache.insert_blooms(modified_blooms_3); + + + let reset_modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + filter.reset_chain_head(&[to_bloom(&topic_4), to_bloom(&topic_5)], 15, 17) + }; + + cache.insert_blooms(reset_modified_blooms); + + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_0), 0, 100), vec![14]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_1), 0, 100), vec![]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_2), 0, 100), vec![]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_3), 0, 100), vec![]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_4), 0, 100), vec![15]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_5), 0, 100), vec![16]); +} + fn for_each_bloom(bytes: &[u8], mut f: F) where F: FnMut(usize, &H2048) { let mut reader = BufReader::new(bytes); let mut line = String::new(); @@ -211,3 +273,5 @@ fn test_chainfilter_real_data_single_search() { assert_eq!(blocks[1], 396348); assert_eq!(blocks[2], 399804); } + + From e63aba73c5724739f00231581a9608879f584cd9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Feb 2016 09:04:44 +0100 Subject: [PATCH 155/753] Remove "unknown" from version string. --- Cargo.lock | 6 ++++++ util/Cargo.toml | 1 + util/src/lib.rs | 1 + util/src/misc.rs | 3 ++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 8bf4a3764..cf747f3cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,6 +241,7 @@ dependencies = [ "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -692,6 +693,11 @@ dependencies = [ "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "target_info" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "term" version = "0.2.14" diff --git a/util/Cargo.toml b/util/Cargo.toml index da4f8e34e..62668fcc1 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -34,6 +34,7 @@ igd = "0.4.2" ethcore-devtools = { path = "../devtools" } libc = "0.2.7" vergen = "0.1" +target_info = "0.1" [features] default = [] diff --git a/util/src/lib.rs b/util/src/lib.rs index 07593e5eb..2b7438cf3 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -108,6 +108,7 @@ extern crate igd; extern crate ethcore_devtools as devtools; extern crate libc; extern crate rustc_version; +extern crate target_info; extern crate vergen; pub mod standard; diff --git a/util/src/misc.rs b/util/src/misc.rs index 22a2bb673..289f1c50c 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -18,6 +18,7 @@ use std::fs::File; use common::*; +use target_info::Target; use rustc_version; include!(concat!(env!("OUT_DIR"), "/version.rs")); @@ -68,5 +69,5 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { - format!("Parity//{}/{}-{}/{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date(), target(), rustc_version::version()) + format!("Parity//{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) } \ No newline at end of file From 4adb7ee969c7badb765099d41c8af2a8e867a10f Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 22 Feb 2016 09:12:15 +0100 Subject: [PATCH 156/753] tests for blockchain reseting chain head and rebuilding blooms --- ethcore/src/blockchain.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 1809debaf..2faf1bd30 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -1020,16 +1020,24 @@ mod tests { fn test_bloom_filter_simple() { let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); - // bloom filter from block 300059 + // block b1 (child of genesis) let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000200000000000000000000000000000000000000000020000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080004000000000000000000000020008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); - // bloom filter from block 300054 + // block b2 (child of b1) let b2 = "f902ccf901f9a04ef46c05763fffc5f7e59f92a7ef438ffccbb578e6e5d0f04e3df8a7fa6c02f6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); + // prepare for fork (b1a, child of genesis) + let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); + + // fork (b2a, child of b1a, with higher total difficulty) + let b2a = "f902ccf901f9a0d6e45b8289d8a18aed656ef9e8477ea385aefd6f825133b4bab9608705e47b87a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); + let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap(); let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let bloom_ba = H2048::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); @@ -1049,6 +1057,24 @@ mod tests { let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); + + // hasn't been forked yet + bc.insert_block(&b1a, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 3); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![2]); + assert_eq!(blocks_ba, vec![]); + + // fork has happend + bc.insert_block(&b2a, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 3); + assert_eq!(blocks_b1, vec![]); + assert_eq!(blocks_b2, vec![]); + assert_eq!(blocks_ba, vec![1, 2]); } #[test] From 61e1720d070cac6d896b8dcd6a5134d5f465b4fb Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 22 Feb 2016 09:54:56 +0100 Subject: [PATCH 157/753] fork back tests --- ethcore/src/blockchain.rs | 50 +++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 2faf1bd30..085976a8d 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -480,13 +480,13 @@ impl BlockChain { while from_details.number > to_details.number { from_branch.push(current_from); current_from = from_details.parent.clone(); - from_details = self.block_details(&from_details.parent).unwrap(); + from_details = self.block_details(&from_details.parent).expect(&format!("1. Expected to find details for block {:?}", from_details.parent)); } while to_details.number > from_details.number { to_branch.push(current_to); current_to = to_details.parent.clone(); - to_details = self.block_details(&to_details.parent).unwrap(); + to_details = self.block_details(&to_details.parent).expect(&format!("2. Expected to find details for block {:?}", to_details.parent)); } assert_eq!(from_details.number, to_details.number); @@ -495,11 +495,11 @@ impl BlockChain { while current_from != current_to { from_branch.push(current_from); current_from = from_details.parent.clone(); - from_details = self.block_details(&from_details.parent).unwrap(); + from_details = self.block_details(&from_details.parent).expect(&format!("3. Expected to find details for block {:?}", from_details.parent)); to_branch.push(current_to); current_to = to_details.parent.clone(); - to_details = self.block_details(&to_details.parent).unwrap(); + to_details = self.block_details(&to_details.parent).expect(&format!("4. Expected to find details for block {:?}", from_details.parent)); } let index = from_branch.len(); @@ -816,6 +816,8 @@ mod tests { use blockchain::{BlockProvider, BlockChain}; use tests::helpers::*; use devtools::*; + use views::BlockView; + use util::uint::U256; #[test] fn valid_tests_extra32() { @@ -1027,10 +1029,13 @@ mod tests { let b2 = "f902ccf901f9a04ef46c05763fffc5f7e59f92a7ef438ffccbb578e6e5d0f04e3df8a7fa6c02f6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); // prepare for fork (b1a, child of genesis) - let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); + let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); // fork (b2a, child of b1a, with higher total difficulty) - let b2a = "f902ccf901f9a0d6e45b8289d8a18aed656ef9e8477ea385aefd6f825133b4bab9608705e47b87a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); + let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); + + // fork back :) + let b3 = "f902ccf901f9a0e6cd7250e4c32b33c906aca30280911c560ac67bd0a05fbeb874f99ac7e7e47aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004003832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap(); @@ -1041,40 +1046,49 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); assert_eq!(blocks_b1, vec![]); assert_eq!(blocks_b2, vec![]); bc.insert_block(&b1, vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![]); bc.insert_block(&b2, vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); // hasn't been forked yet bc.insert_block(&b1a, vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); - let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 3); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); assert_eq!(blocks_ba, vec![]); // fork has happend bc.insert_block(&b2a, vec![]); - let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 3); - let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 3); - let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 3); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); assert_eq!(blocks_b1, vec![]); assert_eq!(blocks_b2, vec![]); assert_eq!(blocks_ba, vec![1, 2]); + + // fork back + bc.insert_block(&b3, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![2]); + assert_eq!(blocks_ba, vec![3]); } #[test] From 8f4c2d98baa65278663afd4672f99d95422a45d0 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 22 Feb 2016 10:11:07 +0100 Subject: [PATCH 158/753] added trailin , --- ethcore/src/blockchain.rs | 4 ++-- ethcore/src/chainfilter/chainfilter.rs | 2 +- ethcore/src/chainfilter/indexer.rs | 2 +- rpc/src/v1/types/filter.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 085976a8d..40a3f0606 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -52,7 +52,7 @@ pub struct CacheSize { /// Blooms cache size. pub blocks_blooms: usize, /// Block receipts size. - pub block_receipts: usize + pub block_receipts: usize, } struct BloomIndexer { @@ -106,7 +106,7 @@ struct ExtrasUpdate { /// New best block (if it has changed). new_best: Option, /// Changed blocks bloom location hashes. - bloom_hashes: HashSet + bloom_hashes: HashSet, } impl CacheSize { diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs index 6b30066f7..e0a281f12 100644 --- a/ethcore/src/chainfilter/chainfilter.rs +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -65,7 +65,7 @@ pub struct ChainFilter<'a, D> where D: FilterDataSource + 'a { data_source: &'a D, - indexer: Indexer + indexer: Indexer, } impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource diff --git a/ethcore/src/chainfilter/indexer.rs b/ethcore/src/chainfilter/indexer.rs index 141a4e7d3..524fab1a9 100644 --- a/ethcore/src/chainfilter/indexer.rs +++ b/ethcore/src/chainfilter/indexer.rs @@ -21,7 +21,7 @@ use chainfilter::BloomIndex; /// Simplifies working with bloom indexes. pub struct Indexer { index_size: usize, - level_sizes: Vec + level_sizes: Vec, } impl Indexer { diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index bb932f349..c5c3604dd 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -26,7 +26,7 @@ use ethcore::client::BlockId; pub enum VariadicValue where T: Deserialize { Single(T), Multiple(Vec), - Null + Null, } impl Deserialize for VariadicValue where T: Deserialize { @@ -54,7 +54,7 @@ pub struct Filter { #[serde(rename="toBlock")] pub to_block: Option, pub address: Option, - pub topics: Option> + pub topics: Option>, } impl Into for Filter { From 2be4f2f73767017f8490f1d48f381a8729cb8704 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 22 Feb 2016 10:14:31 +0100 Subject: [PATCH 159/753] added trailin , --- ethcore/src/blockchain.rs | 4 ++-- ethcore/src/extras.rs | 2 +- ethcore/src/log_entry.rs | 2 +- rpc/src/v1/types/log.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 40a3f0606..8b83ef3e0 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -57,7 +57,7 @@ pub struct CacheSize { struct BloomIndexer { index_size: usize, - levels: u8 + levels: u8, } impl BloomIndexer { @@ -236,7 +236,7 @@ pub struct BlockChain { cache_man: RwLock, // blooms indexing - bloom_indexer: BloomIndexer + bloom_indexer: BloomIndexer, } impl FilterDataSource for BlockChain { diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index c7102dba9..64d8afcb9 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -314,7 +314,7 @@ impl Encodable for TransactionAddress { /// Contains all block receipts. #[derive(Clone)] pub struct BlockReceipts { - pub receipts: Vec + pub receipts: Vec, } impl BlockReceipts { diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index a7d409833..a75e6fcc1 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -90,7 +90,7 @@ pub struct LocalizedLogEntry { /// Index of transaction within block. pub transaction_index: usize, /// Log position in the block. - pub log_index: usize + pub log_index: usize, } impl Deref for LocalizedLogEntry { diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 83880a222..0629c5534 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -33,7 +33,7 @@ pub struct Log { #[serde(rename="transactionIndex")] transaction_index: U256, #[serde(rename="logIndex")] - log_index: U256 + log_index: U256, } impl From for Log { From 90184658a7ed095816d038755bf0210033250791 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 22 Feb 2016 13:41:38 +0100 Subject: [PATCH 160/753] jsonrpc security, cors headers, fixed #359 --- Cargo.lock | 5 +++-- parity/main.rs | 16 +++++++++------- rpc/Cargo.toml | 2 +- rpc/src/lib.rs.in | 4 ++-- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf747f3cc..8be46a773 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,7 +206,7 @@ dependencies = [ "ethcore-util 0.9.99", "ethsync 0.9.99", "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -373,11 +373,12 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" -version = "1.1.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/parity/main.rs b/parity/main.rs index f4b7880ab..2e86608ef 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -52,7 +52,7 @@ use ethsync::EthSync; use docopt::Docopt; use daemonize::Daemonize; -const USAGE: &'static str = " +const USAGE: &'static str = r#" Parity. Ethereum Client. By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf. Copyright 2015, 2016 Ethcore (UK) Limited @@ -71,8 +71,8 @@ Options: --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect. --address URL Equivalent to --listen-address URL --public-address URL. - --peers NUM Try to manintain that many peers [default: 25]. - --no-discovery Disable new peer discovery. + --peers NUM Try to manintain that many peers [default: 25]. + --no-discovery Disable new peer discovery. --upnp Use UPnP to try to figure out the correct network settings. --node-key KEY Specify node secret key as hex string. @@ -81,11 +81,12 @@ Options: -j --jsonrpc Enable the JSON-RPC API sever. --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. + --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. -"; +"#; #[derive(Debug, RustcDecodable)] struct Args { @@ -107,6 +108,7 @@ struct Args { flag_cache_max_size: usize, flag_jsonrpc: bool, flag_jsonrpc_url: String, + flag_jsonrpc_cors: String, flag_logging: Option, flag_version: bool, } @@ -127,7 +129,7 @@ fn setup_log(init: &Option) { } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, url: &str) { +fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_domain: &str) { use rpc::v1::*; let mut server = rpc::HttpServer::new(1); @@ -135,7 +137,7 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str) { server.add_delegate(EthClient::new(client.clone(), sync.clone()).to_delegate()); server.add_delegate(EthFilterClient::new(client).to_delegate()); server.add_delegate(NetClient::new(sync).to_delegate()); - server.start_async(url); + server.start_async(url, cors_domain); } #[cfg(not(feature = "rpc"))] @@ -279,7 +281,7 @@ impl Configuration { // Setup rpc if self.args.flag_jsonrpc { - setup_rpc_server(service.client(), sync.clone(), &self.args.flag_jsonrpc_url); + setup_rpc_server(service.client(), sync.clone(), &self.args.flag_jsonrpc_url, &self.args.flag_jsonrpc_cors); } // Register IO handler diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index be06316a4..1394c206f 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -12,7 +12,7 @@ build = "build.rs" serde = "0.6.7" serde_json = "0.6.0" jsonrpc-core = "1.1" -jsonrpc-http-server = "1.1" +jsonrpc-http-server = "2.0" ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } diff --git a/rpc/src/lib.rs.in b/rpc/src/lib.rs.in index f09a25be8..e17f2b3bb 100644 --- a/rpc/src/lib.rs.in +++ b/rpc/src/lib.rs.in @@ -23,8 +23,8 @@ impl HttpServer { } /// Start server asynchronously in new thread - pub fn start_async(self, addr: &str) { + pub fn start_async(self, addr: &str, cors_domain: &str) { let server = jsonrpc_http_server::Server::new(self.handler, self.threads); - server.start_async(addr) + server.start_async(addr, jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain.to_owned())) } } From 077c5662a86d05eea01b011727393dfbc2559461 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 22 Feb 2016 13:47:25 +0100 Subject: [PATCH 161/753] Fixed a warning --- util/src/kvdb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index fa74553fb..2866925cb 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -55,7 +55,7 @@ pub struct DatabaseIterator<'a> { impl<'a> Iterator for DatabaseIterator<'a> { type Item = (Box<[u8]>, Box<[u8]>); - #[allow(type_complexity)] + #[cfg_attr(feature="dev", allow(type_complexity))] fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> { self.iter.next() } From 64d566ff523da2c913138bd4805567dc2682f83a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Feb 2016 13:58:41 +0100 Subject: [PATCH 162/753] Manage final user-input errors. --- parity/main.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index f4b7880ab..07741ee2a 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -214,17 +214,17 @@ impl Configuration { let mut public_address = None; if let Some(ref a) = self.args.flag_address { - public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address")); + public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --address", a))); listen_address = public_address; } if listen_address.is_none() { - listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).expect("Invalid listen address given with --listen-address")); + listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --listen-address", self.args.flag_listen_address))); } if let Some(ref a) = self.args.flag_public_address { if public_address.is_some() { - panic!("Conflicting flags: --address and --public-address"); + die!("Conflicting flags provided: --address and --public-address"); } - public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --public-address")); + public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --public-address", a))); } (listen_address, public_address) } @@ -236,7 +236,7 @@ impl Configuration { let (listen, public) = self.net_addresses(); ret.listen_address = listen; ret.public_address = public; - ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); + ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3())); ret.discovery_enabled = !self.args.flag_no_discovery; ret.ideal_peers = self.args.flag_peers; let mut net_path = PathBuf::from(&self.path()); @@ -279,6 +279,7 @@ impl Configuration { // Setup rpc if self.args.flag_jsonrpc { + SocketAddr::from_str(&self.args.flag_jsonrpc_url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen address given with --jsonrpc-url. Should be of the form 'IP:port'.", self.args.flag_jsonrpc_url)); setup_rpc_server(service.client(), sync.clone(), &self.args.flag_jsonrpc_url); } From 5917290562511487e95a1504ae7e087447d9c9e8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Feb 2016 13:59:25 +0100 Subject: [PATCH 163/753] Remove unneeded code, fix minor potential issue with length. --- util/src/network/discovery.rs | 3 --- util/src/network/node_table.rs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 01d2da52c..e2fd1c269 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -276,9 +276,6 @@ impl Discovery { } pub fn writable(&mut self) { - if self.send_queue.is_empty() { - return; - } while !self.send_queue.is_empty() { let data = self.send_queue.pop_front().unwrap(); match self.udp_socket.send_to(&data.payload, &data.address) { diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index ec6bad2aa..868863e8c 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -163,7 +163,7 @@ impl Display for Node { impl FromStr for Node { type Err = UtilError; fn from_str(s: &str) -> Result { - let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" { + let (id, endpoint) = if s.len() > 136 && &s[0..8] == "enode://" && &s[136..137] == "@" { (try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..]))) } else { From 4b69b96f9bef717f08c50c46ad7280f4513e7dc1 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 22 Feb 2016 15:14:35 +0100 Subject: [PATCH 164/753] added assert checking bloom index size --- ethcore/src/blockchain.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 8b83ef3e0..2b812e92d 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -663,6 +663,7 @@ impl BlockChain { let mut blocks_blooms = acc .entry(location.hash.clone()) .or_insert_with(|| self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new)); + assert_eq!(self.bloom_indexer.index_size, blocks_blooms.blooms.len()); blocks_blooms.blooms[location.index] = bloom; } acc From 753f52fc22b2f5667dd477cc38eac62e1c667eb3 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 22 Feb 2016 20:07:56 +0300 Subject: [PATCH 165/753] geth import finish --- ethtools/Cargo.toml | 2 + ...--3f49624084b67849c7b4e805c5988c21a430f9d9 | 22 +++++++- ...--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf | 22 +++++++- ethtools/src/geth_keys.rs | 50 ++++++++++++++++++- ethtools/src/lib.rs | 2 + 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/ethtools/Cargo.toml b/ethtools/Cargo.toml index 5529c1d33..0ff934421 100644 --- a/ethtools/Cargo.toml +++ b/ethtools/Cargo.toml @@ -8,3 +8,5 @@ authors = ["Ethcore "] [dependencies] ethcore-util = { path = "../util" } +rustc-serialize = "0.3" +ethcore-devtools = { path = "../devtools" } diff --git a/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 b/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 index a62d3056c..afc376774 100644 --- a/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 +++ b/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 @@ -1 +1,21 @@ -{"address":"3f49624084b67849c7b4e805c5988c21a430f9d9","Crypto":{"cipher":"aes-128-ctr","ciphertext":"9f27e3dd4fc73e7103ed61e5493662189a3eb52223ae49e3d1deacc04c889eae","cipherparams":{"iv":"457494bf05f2618c397dc74dbb5181c0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"db14edb18c41ee7f5ec4397df89c3a2ae4d0af60884c52bb54ce490574f8df33"},"mac":"572d24532438d31fdf513c744a3ff26c933ffda5744ee42bc71661cbe3f2112e"},"id":"62a0ad73-556d-496a-8e1c-0783d30d3ace","version":3} \ No newline at end of file +{ + "address": "3f49624084b67849c7b4e805c5988c21a430f9d9", + "Crypto": { + "cipher": "aes-128-ctr", + "ciphertext": "9f27e3dd4fc73e7103ed61e5493662189a3eb52223ae49e3d1deacc04c889eae", + "cipherparams": { + "iv": "457494bf05f2618c397dc74dbb5181c0" + }, + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "db14edb18c41ee7f5ec4397df89c3a2ae4d0af60884c52bb54ce490574f8df33" + }, + "mac": "572d24532438d31fdf513c744a3ff26c933ffda5744ee42bc71661cbe3f2112e" + }, + "id": "62a0ad73-556d-496a-8e1c-0783d30d3ace", + "version": 3 +} diff --git a/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf b/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf index b6caa1c47..b14922037 100644 --- a/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf +++ b/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf @@ -1 +1,21 @@ -{"address":"5ba4dcf897e97c2bdf8315b9ef26c13c085988cf","Crypto":{"cipher":"aes-128-ctr","ciphertext":"d4a08ec930163778273920f6ad1d49b71836337be6fd9863993ac700a612fddd","cipherparams":{"iv":"89ce5ec129fc27cd5bcbeb8c92bdad50"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"612ab108dc37e69ee8af37a7b24bf7f2234086d7bbf945bacdeccce331f7f84a"},"mac":"4152caa7444e06784223d735cea80cd2690b4c587ad8db3d5529442227b25695"},"id":"35086353-fb12-4029-b56b-033cd61ce35b","version":3} \ No newline at end of file +{ + "address": "5ba4dcf897e97c2bdf8315b9ef26c13c085988cf", + "Crypto": { + "cipher": "aes-128-ctr", + "ciphertext": "d4a08ec930163778273920f6ad1d49b71836337be6fd9863993ac700a612fddd", + "cipherparams": { + "iv": "89ce5ec129fc27cd5bcbeb8c92bdad50" + }, + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "612ab108dc37e69ee8af37a7b24bf7f2234086d7bbf945bacdeccce331f7f84a" + }, + "mac": "4152caa7444e06784223d735cea80cd2690b4c587ad8db3d5529442227b25695" + }, + "id": "35086353-fb12-4029-b56b-033cd61ce35b", + "version": 3 +} diff --git a/ethtools/src/geth_keys.rs b/ethtools/src/geth_keys.rs index 58dc2a0b1..3148407dd 100644 --- a/ethtools/src/geth_keys.rs +++ b/ethtools/src/geth_keys.rs @@ -17,13 +17,18 @@ //! Geth keys import/export tool use util::hash::*; +use util::keys::store::SecretStore; +use util::keys::directory::KeyFileContent; use std::path::Path; use std::result::*; use std::fs; use std::str::FromStr; +use std::io; +use std::io::Read; +use rustc_serialize::json::Json; /// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)` -pub fn enumerate_geth_keys(path: &Path) -> Result, ::std::io::Error> { +pub fn enumerate_geth_keys(path: &Path) -> Result, io::Error> { let mut entries = Vec::new(); for entry in try!(fs::read_dir(path)) { let entry = try!(entry); @@ -44,14 +49,57 @@ pub fn enumerate_geth_keys(path: &Path) -> Result, ::std: Ok(entries) } +#[derive(Debug)] +pub enum ImportError { + IoError(io::Error), + FormatError, +} + +impl From for ImportError { + fn from (err: io::Error) -> ImportError { + ImportError::IoError(err) + } +} + +pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) -> Result<(), ImportError> { + let mut file = try!(fs::File::open(geth_keyfile_path)); + let mut buf = String::new(); + try!(file.read_to_string(&mut buf)); + + let mut json = match Json::from_str(&buf) { + Ok(parsed_json) => try!(parsed_json.as_object().ok_or(ImportError::FormatError)).clone(), + Err(_) => { return Err(ImportError::FormatError); } + }; + let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::FormatError)).clone(); + json.insert("crypto".to_owned(), Json::Object(crypto_object.clone())); + json.remove("Crypto"); + match KeyFileContent::load(&Json::Object(json.clone())) { + Ok(key_file) => try!(secret_store.import_key(key_file)), + Err(_) => { return Err(ImportError::FormatError); } + }; + Ok(()) +} + #[cfg(test)] mod tests { use super::*; use std::path::Path; + use util::hash::*; + use util::keys::store::SecretStore; + use std::str::FromStr; #[test] fn can_enumerate() { let keys = enumerate_geth_keys(Path::new("res/geth_keystore")).unwrap(); assert_eq!(2, keys.len()); } + + #[test] + fn can_import() { + let temp = ::devtools::RandomTempPath::new(); + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_key(&mut secret_store, Path::new("res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9")).unwrap(); + let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); + assert!(key.is_some()); + } } diff --git a/ethtools/src/lib.rs b/ethtools/src/lib.rs index 41dd69cf9..1509f6d81 100644 --- a/ethtools/src/lib.rs +++ b/ethtools/src/lib.rs @@ -17,5 +17,7 @@ //! Ethereum Tools Library extern crate ethcore_util as util; +extern crate rustc_serialize; +extern crate ethcore_devtools as devtools; pub mod geth_keys; From 61a3e687f5b05b11c92dc3cbf98348ce25d864e9 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 22 Feb 2016 20:08:16 +0300 Subject: [PATCH 166/753] store extra interface --- util/src/keys/directory.rs | 12 +++++++++- util/src/keys/store.rs | 46 +++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 298f67b99..e05ae4877 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -381,6 +381,16 @@ impl KeyFileContent { } } + pub fn load(json: &Json) -> Result { + match Self::from_json(json) { + Ok(key_file) => Ok(key_file), + Err(e) => { + warn!(target: "sstore", "Error parsing json for key: {:?}", e); + Err(()) + } + } + } + /// Returns key file version if it is known. pub fn version(&self) -> Option { match self.version { @@ -410,7 +420,7 @@ impl KeyFileContent { Ok(id) => id }; - let account = as_object.get("account").and_then(|json| json.as_string()).and_then( + let account = as_object.get("address").and_then(|json| json.as_string()).and_then( |account_text| match Address::from_str(account_text) { Ok(account) => Some(account), Err(_) => None }); let crypto = match as_object.get("crypto") { diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 284c78b2c..7aa6d2e76 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -64,8 +64,12 @@ impl SecretStore { pub fn new() -> SecretStore { let mut path = ::std::env::home_dir().expect("Failed to get home dir"); path.push("keystore"); + Self::new_in(&path) + } + + pub fn new_in(path: &Path) -> SecretStore { SecretStore { - directory: KeyDirectory::new(&path) + directory: KeyDirectory::new(path) } } @@ -285,6 +289,25 @@ mod tests { result } + fn pregenerate_accounts(temp: &RandomTempPath, count: usize) -> Vec { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + let mut result = Vec::new(); + for i in 0..count { + let mut key_file = + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32)); + key_file.account = Some(x!(i as u64)); + } + result + } + #[test] fn can_get() { let temp = RandomTempPath::create_dir(); @@ -319,5 +342,26 @@ mod tests { assert_eq!(4, sstore.directory.list().unwrap().len()) } + #[test] + fn can_import_account() { + let temp = RandomTempPath::create_dir(); + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut key_file = + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32)); + key_file.account = Some(Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); + let mut sstore = SecretStore::new_test(&temp); + + sstore.import_key(key_file); + + assert_eq!(1, sstore.accounts().unwrap().len()); + assert!(sstore.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()).is_some()); + } } From a6c41514d423bb9037f9f9b42bbb07cb15328a16 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Feb 2016 18:10:21 +0100 Subject: [PATCH 167/753] Update docs. --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index f4b7880ab..86d8d11a8 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -74,7 +74,7 @@ Options: --peers NUM Try to manintain that many peers [default: 25]. --no-discovery Disable new peer discovery. --upnp Use UPnP to try to figure out the correct network settings. - --node-key KEY Specify node secret key as hex string. + --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. From 72d071922341bec2e2ae7ca2c3dc01f3d327b4c2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 22 Feb 2016 18:11:53 +0100 Subject: [PATCH 168/753] Update docs. --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 07741ee2a..328bfc0e2 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -74,7 +74,7 @@ Options: --peers NUM Try to manintain that many peers [default: 25]. --no-discovery Disable new peer discovery. --upnp Use UPnP to try to figure out the correct network settings. - --node-key KEY Specify node secret key as hex string. + --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. From 93f2ee66bc2f9561b31abc68adf04fe00f35a7f5 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 22 Feb 2016 22:19:33 +0300 Subject: [PATCH 169/753] geth directory import --- ethtools/Cargo.toml | 1 + ethtools/src/geth_keys.rs | 31 +++++++++++++++++++++++++++++-- ethtools/src/lib.rs | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ethtools/Cargo.toml b/ethtools/Cargo.toml index 0ff934421..87e101b4d 100644 --- a/ethtools/Cargo.toml +++ b/ethtools/Cargo.toml @@ -10,3 +10,4 @@ authors = ["Ethcore "] ethcore-util = { path = "../util" } rustc-serialize = "0.3" ethcore-devtools = { path = "../devtools" } +log = "0.3" diff --git a/ethtools/src/geth_keys.rs b/ethtools/src/geth_keys.rs index 3148407dd..c1a7782d7 100644 --- a/ethtools/src/geth_keys.rs +++ b/ethtools/src/geth_keys.rs @@ -19,7 +19,7 @@ use util::hash::*; use util::keys::store::SecretStore; use util::keys::directory::KeyFileContent; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::result::*; use std::fs; use std::str::FromStr; @@ -61,6 +61,7 @@ impl From for ImportError { } } +/// Imports one geth key to the store pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) -> Result<(), ImportError> { let mut file = try!(fs::File::open(geth_keyfile_path)); let mut buf = String::new(); @@ -80,6 +81,19 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) Ok(()) } +pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> { + let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory)); + for &(ref address, ref file_path) in geth_files.iter() { + let mut path = PathBuf::new(); + path.push(geth_keyfiles_directory); + path.push(file_path); + if let Err(e) = import_geth_key(secret_store, Path::new(&path)) { + warn!("Skipped geth address {}, error importing: {:?}", address, e) + } + } + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -96,10 +110,23 @@ mod tests { #[test] fn can_import() { - let temp = ::devtools::RandomTempPath::new(); + let temp = ::devtools::RandomTempPath::create_dir(); let mut secret_store = SecretStore::new_in(temp.as_path()); import_geth_key(&mut secret_store, Path::new("res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9")).unwrap(); let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); assert!(key.is_some()); } + + #[test] + fn can_import_directory() { + let temp = ::devtools::RandomTempPath::create_dir(); + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_keys(&mut secret_store, Path::new("res/geth_keystore")).unwrap(); + + let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); + assert!(key.is_some()); + + let key = secret_store.account(&Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()); + assert!(key.is_some()); + } } diff --git a/ethtools/src/lib.rs b/ethtools/src/lib.rs index 1509f6d81..4cf365f5f 100644 --- a/ethtools/src/lib.rs +++ b/ethtools/src/lib.rs @@ -19,5 +19,6 @@ extern crate ethcore_util as util; extern crate rustc_serialize; extern crate ethcore_devtools as devtools; +#[macro_use] extern crate log; pub mod geth_keys; From e604c97a435dd763aec9fad8fbceecd65bfe4cf4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 22 Feb 2016 23:12:13 +0300 Subject: [PATCH 170/753] more account tests --- ethtools/src/geth_keys.rs | 18 ++++++++++++ util/src/keys/directory.rs | 47 ++++++++++++++++++++++++++++-- util/src/keys/store.rs | 59 ++++++++++++++++++++++++++------------ 3 files changed, 103 insertions(+), 21 deletions(-) diff --git a/ethtools/src/geth_keys.rs b/ethtools/src/geth_keys.rs index c1a7782d7..7d6c7adef 100644 --- a/ethtools/src/geth_keys.rs +++ b/ethtools/src/geth_keys.rs @@ -49,9 +49,12 @@ pub fn enumerate_geth_keys(path: &Path) -> Result, io::Er Ok(entries) } +/// Geth import error #[derive(Debug)] pub enum ImportError { + /// Io error reading geth file IoError(io::Error), + /// format error FormatError, } @@ -81,6 +84,7 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) Ok(()) } +/// Imports all geth keys in the directory pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> { let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory)); for &(ref address, ref file_path) in geth_files.iter() { @@ -129,4 +133,18 @@ mod tests { let key = secret_store.account(&Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()); assert!(key.is_some()); } + + #[test] + fn can_decrypt_with_imported() { + use util::keys::store::EncryptedHashMap; + use util::bytes::*; + + let temp = ::devtools::RandomTempPath::create_dir(); + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_keys(&mut secret_store, Path::new("res/geth_keystore")).unwrap(); + + let val = secret_store.get::(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap(), "123"); + assert!(val.is_ok()); + assert_eq!(vec![0u8, 10], val.unwrap()); + } } diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index e05ae4877..233b8b974 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -381,6 +381,7 @@ impl KeyFileContent { } } + /// Loads key from valid json, returns error and records warning if key is mallformed pub fn load(json: &Json) -> Result { match Self::from_json(json) { Ok(key_file) => Ok(key_file), @@ -444,6 +445,7 @@ impl KeyFileContent { map.insert("id".to_owned(), Json::String(uuid_to_string(&self.id))); map.insert("version".to_owned(), Json::U64(CURRENT_DECLARED_VERSION)); map.insert("crypto".to_owned(), self.crypto.to_json()); + if let Some(ref address) = self.account { map.insert("address".to_owned(), Json::String(format!("{:?}", address))); } Json::Object(map) } } @@ -670,7 +672,7 @@ mod file_tests { } #[test] - fn can_read_scrypt_krf() { + fn can_read_scrypt_kdf() { let json = Json::from_str( r#" { @@ -706,6 +708,47 @@ mod file_tests { } } + #[test] + fn can_read_scrypt_kdf_params() { + let json = Json::from_str( + r#" + { + "crypto" : { + "cipher" : "aes-128-ctr", + "cipherparams" : { + "iv" : "83dbcc02d8ccb40e466191a123791e0e" + }, + "ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c", + "kdf" : "scrypt", + "kdfparams" : { + "dklen" : 32, + "n" : 262144, + "r" : 1, + "p" : 8, + "salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19" + }, + "mac" : "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097" + }, + "id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6", + "version" : 3 + } + "#).unwrap(); + + match KeyFileContent::from_json(&json) { + Ok(key_file) => { + match key_file.crypto.kdf { + KeyFileKdf::Scrypt(scrypt_params) => { + assert_eq!(262144, scrypt_params.n); + assert_eq!(1, scrypt_params.r); + assert_eq!(8, scrypt_params.p); + }, + _ => { panic!("expected kdf params of crypto to be of scrypt type" ); } + } + }, + Err(e) => panic!("Error parsing valid file: {:?}", e) + } + } + #[test] fn can_return_error_no_id() { let json = Json::from_str( @@ -861,7 +904,7 @@ mod file_tests { panic!("Should be error of no identifier, got ok"); }, Err(KeyFileParseError::Crypto(CryptoParseError::Scrypt(_))) => { }, - Err(other_error) => { panic!("should be error of no identifier, got {:?}", other_error); } + Err(other_error) => { panic!("should be scrypt parse error, got {:?}", other_error); } } } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 7aa6d2e76..1fdb1e8a3 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -19,11 +19,12 @@ use keys::directory::*; use common::*; use rcrypto::pbkdf2::*; +use rcrypto::scrypt::*; use rcrypto::hmac::*; use crypto; const KEY_LENGTH: u32 = 32; -const KEY_ITERATIONS: u32 = 4096; +const KEY_ITERATIONS: u32 = 10240; const KEY_LENGTH_AES: u32 = KEY_LENGTH/2; const KEY_LENGTH_USIZE: usize = KEY_LENGTH as usize; @@ -60,13 +61,14 @@ pub struct SecretStore { } impl SecretStore { - /// new instance of Secret Store + /// new instance of Secret Store in default home directory pub fn new() -> SecretStore { let mut path = ::std::env::home_dir().expect("Failed to get home dir"); path.push("keystore"); Self::new_in(&path) } + /// new instance of Secret Store in specific directory pub fn new_in(path: &Path) -> SecretStore { SecretStore { directory: KeyDirectory::new(path) @@ -94,6 +96,7 @@ impl SecretStore { accounts.first().and_then(|&(_, ref key_id)| Some(key_id.clone())) } + /// Imports pregenerated key, returns error if not saved correctly pub fn import_key(&mut self, key_file: KeyFileContent) -> Result<(), ::std::io::Error> { try!(self.directory.save(key_file)); Ok(()) @@ -120,6 +123,15 @@ fn derive_key(password: &str, salt: &H256) -> (Bytes, Bytes) { derive_key_iterations(password, salt, KEY_ITERATIONS) } +fn derive_key_scrypt(password: &str, salt: &H256, n: u32, p: u32, r: u32) -> (Bytes, Bytes) { + let mut derived_key = vec![0u8; KEY_LENGTH_USIZE]; + let scrypt_params = ScryptParams::new(n as u8, r, p); + scrypt(password.as_bytes(), &salt.as_slice(), &scrypt_params, &mut derived_key); + let derived_right_bits = &derived_key[0..KEY_LENGTH_AES_USIZE]; + let derived_left_bits = &derived_key[KEY_LENGTH_AES_USIZE..KEY_LENGTH_USIZE]; + (derived_right_bits.to_vec(), derived_left_bits.to_vec()) +} + fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes { let mut mac = vec![0u8; KEY_LENGTH_AES_USIZE + cipher_text.len()]; mac[0..KEY_LENGTH_AES_USIZE].clone_from_slice(derived_left_bits); @@ -131,24 +143,22 @@ impl EncryptedHashMap for SecretStore { fn get(&self, key: &H128, password: &str) -> Result { match self.directory.get(key) { Some(key_file) => { - let decrypted_bytes = match key_file.crypto.kdf { - KeyFileKdf::Pbkdf2(ref params) => { - let (derived_left_bits, derived_right_bits) = derive_key_iterations(password, ¶ms.salt, params.c); - if derive_mac(&derived_right_bits, &key_file.crypto.cipher_text) - .sha3() != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } - - let mut val = vec![0u8; key_file.crypto.cipher_text.len()]; - match key_file.crypto.cipher_type { - CryptoCipherType::Aes128Ctr(ref iv) => { - crypto::aes::decrypt(&derived_left_bits, &iv.as_slice(), &key_file.crypto.cipher_text, &mut val); - } - } - val - } - _ => { unimplemented!(); } + let (derived_left_bits, derived_right_bits) = match key_file.crypto.kdf { + KeyFileKdf::Pbkdf2(ref params) => derive_key_iterations(password, ¶ms.salt, params.c), + KeyFileKdf::Scrypt(ref params) => derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r) }; - match Value::from_bytes(&decrypted_bytes) { + if derive_mac(&derived_right_bits, &key_file.crypto.cipher_text) + .sha3() != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } + + let mut val = vec![0u8; key_file.crypto.cipher_text.len()]; + match key_file.crypto.cipher_type { + CryptoCipherType::Aes128Ctr(ref iv) => { + crypto::aes::decrypt(&derived_left_bits, &iv.as_slice(), &key_file.crypto.cipher_text, &mut val); + } + }; + + match Value::from_bytes(&val) { Ok(value) => Ok(value), Err(bytes_error) => Err(EncryptedHashMapError::InvalidValueFormat(bytes_error)) } @@ -304,6 +314,8 @@ mod tests { 262144, 32)); key_file.account = Some(x!(i as u64)); + result.push(key_file.id.clone()); + write_sstore.import_key(key_file).unwrap(); } result } @@ -359,9 +371,18 @@ mod tests { let mut sstore = SecretStore::new_test(&temp); - sstore.import_key(key_file); + sstore.import_key(key_file).unwrap(); assert_eq!(1, sstore.accounts().unwrap().len()); assert!(sstore.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()).is_some()); } + + #[test] + fn can_list_accounts() { + let temp = RandomTempPath::create_dir(); + pregenerate_accounts(&temp, 30); + let sstore = SecretStore::new_test(&temp); + let accounts = sstore.accounts().unwrap(); + assert_eq!(30, accounts.len()); + } } From 4061799e902901772da2171597df0b5d5b0933d2 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 22 Feb 2016 23:40:38 +0300 Subject: [PATCH 171/753] scrypto decrypt fix --- ethtools/src/geth_keys.rs | 24 +++++++++++++++++++++++- util/src/keys/store.rs | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/ethtools/src/geth_keys.rs b/ethtools/src/geth_keys.rs index 7d6c7adef..1a6fb75d4 100644 --- a/ethtools/src/geth_keys.rs +++ b/ethtools/src/geth_keys.rs @@ -134,6 +134,28 @@ mod tests { assert!(key.is_some()); } + #[test] + fn imports_as_scrypt_keys() { + use util::keys::directory::{KeyDirectory, KeyFileKdf}; + let temp = ::devtools::RandomTempPath::create_dir(); + { + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_keys(&mut secret_store, Path::new("res/geth_keystore")).unwrap(); + } + + let key_directory = KeyDirectory::new(&temp.as_path()); + let key_file = key_directory.get(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap()).unwrap(); + + match key_file.crypto.kdf { + KeyFileKdf::Scrypt(scrypt_params) => { + assert_eq!(262144, scrypt_params.n); + assert_eq!(8, scrypt_params.r); + assert_eq!(1, scrypt_params.p); + }, + _ => { panic!("expected kdf params of crypto to be of scrypt type" ); } + } + } + #[test] fn can_decrypt_with_imported() { use util::keys::store::EncryptedHashMap; @@ -145,6 +167,6 @@ mod tests { let val = secret_store.get::(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap(), "123"); assert!(val.is_ok()); - assert_eq!(vec![0u8, 10], val.unwrap()); + assert_eq!(32, val.unwrap().len()); } } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 1fdb1e8a3..b6ae84990 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -125,7 +125,7 @@ fn derive_key(password: &str, salt: &H256) -> (Bytes, Bytes) { fn derive_key_scrypt(password: &str, salt: &H256, n: u32, p: u32, r: u32) -> (Bytes, Bytes) { let mut derived_key = vec![0u8; KEY_LENGTH_USIZE]; - let scrypt_params = ScryptParams::new(n as u8, r, p); + let scrypt_params = ScryptParams::new(n.trailing_zeros() as u8, r, p); scrypt(password.as_bytes(), &salt.as_slice(), &scrypt_params, &mut derived_key); let derived_right_bits = &derived_key[0..KEY_LENGTH_AES_USIZE]; let derived_left_bits = &derived_key[KEY_LENGTH_AES_USIZE..KEY_LENGTH_USIZE]; From bceafe9094eaf21a4a233b76fb9d3df0a6c638f5 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 23 Feb 2016 00:05:28 +0300 Subject: [PATCH 172/753] fix import statement --- util/src/keys/store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index b6ae84990..3c2aef7c3 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -356,8 +356,8 @@ mod tests { #[test] fn can_import_account() { - let temp = RandomTempPath::create_dir(); use keys::directory::{KeyFileContent, KeyFileCrypto}; + let temp = RandomTempPath::create_dir(); let mut key_file = KeyFileContent::new( KeyFileCrypto::new_pbkdf2( From 000d2446b5850a1f7cee8de2749bd0757c29cd0c Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 22 Feb 2016 23:05:27 +0100 Subject: [PATCH 173/753] EIP8 --- util/src/crypto.rs | 22 +- util/src/network/connection.rs | 2 +- util/src/network/discovery.rs | 100 +++++++-- util/src/network/handshake.rs | 366 +++++++++++++++++++++++++++++---- 4 files changed, 429 insertions(+), 61 deletions(-) diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 596265cd0..2d5516b6f 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -254,7 +254,7 @@ pub mod ecies { use crypto::*; /// Encrypt a message with a public key - pub fn encrypt(public: &Public, plain: &[u8]) -> Result { + pub fn encrypt(public: &Public, shared_mac: &[u8], plain: &[u8]) -> Result { use ::rcrypto::digest::Digest; use ::rcrypto::sha2::Sha256; use ::rcrypto::hmac::Hmac; @@ -284,13 +284,14 @@ pub mod ecies { let cipher_iv = &msgd[64..(64 + 16 + plain.len())]; hmac.input(cipher_iv); } + hmac.input(shared_mac); hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]); } Ok(msg) } /// Decrypt a message with a secret key - pub fn decrypt(secret: &Secret, encrypted: &[u8]) -> Result { + pub fn decrypt(secret: &Secret, shared_mac: &[u8], encrypted: &[u8]) -> Result { use ::rcrypto::digest::Digest; use ::rcrypto::sha2::Sha256; use ::rcrypto::hmac::Hmac; @@ -322,6 +323,7 @@ pub mod ecies { // Verify tag let mut hmac = Hmac::new(Sha256::new(), &mkey); hmac.input(cipher_with_iv); + hmac.input(shared_mac); let mut mac = H256::new(); hmac.raw_result(&mut mac); if &mac[..] != msg_mac { @@ -405,4 +407,20 @@ mod tests { let pair = KeyPair::from_secret(h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2")).unwrap(); assert_eq!(pair.public().hex(), "101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c"); } + + #[test] + fn ecies_shared() { + let kp = KeyPair::create().unwrap(); + let message = b"So many books, so little time"; + + let shared = b"shared"; + let wrong_shared = b"incorrect"; + let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap(); + assert!(encrypted[..] != message[..]); + assert_eq!(encrypted[0], 0x04); + + assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err()); + let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap(); + assert_eq!(decrypted[..message.len()], message[..]); + } } diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index a7396ff33..55e688c91 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -279,7 +279,7 @@ impl EncryptedConnection { /// Create an encrypted connection out of the handshake. Consumes a handshake object. pub fn new(handshake: &mut Handshake) -> Result { - let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public)); + let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_ephemeral)); let mut nonce_material = H512::new(); if handshake.originated { handshake.remote_nonce.copy_to(&mut nonce_material[0..32]); diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 01d2da52c..e00837f8c 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -85,7 +85,8 @@ pub struct Discovery { discovery_id: NodeId, discovery_nodes: HashSet, node_buckets: Vec, - send_queue: VecDeque + send_queue: VecDeque, + check_timestamps: bool, } pub struct TableUpdates { @@ -107,6 +108,7 @@ impl Discovery { node_buckets: (0..NODE_BINS).map(|_| NodeBucket::new()).collect(), udp_socket: socket, send_queue: VecDeque::new(), + check_timestamps: true, } } @@ -347,20 +349,20 @@ impl Discovery { } } + fn check_timestamp(&self, timestamp: u64) -> Result<(), NetworkError>{ + if self.check_timestamps && timestamp < time::get_time().sec as u64{ + debug!(target: "discovery", "Expired packet"); + return Err(NetworkError::Expired); + } + Ok(()) + } + fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { trace!(target: "discovery", "Got Ping from {:?}", &from); - let version: u32 = try!(rlp.val_at(0)); - if version != PROTOCOL_VERSION { - debug!(target: "discovery", "Unexpected protocol version: {}", version); - return Err(NetworkError::BadProtocol); - } let source = try!(NodeEndpoint::from_rlp(&try!(rlp.at(1)))); let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(2)))); let timestamp: u64 = try!(rlp.val_at(3)); - if timestamp < time::get_time().sec as u64{ - debug!(target: "discovery", "Expired ping"); - return Err(NetworkError::Expired); - } + try!(self.check_timestamp(timestamp)); let mut added_map = HashMap::new(); let entry = NodeEntry { id: node.clone(), endpoint: source.clone() }; if !entry.endpoint.is_valid() || !entry.endpoint.is_global() { @@ -384,9 +386,7 @@ impl Discovery { // TODO: validate pong packet let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(0)))); let timestamp: u64 = try!(rlp.val_at(2)); - if timestamp < time::get_time().sec as u64 { - return Err(NetworkError::Expired); - } + try!(self.check_timestamp(timestamp)); let mut entry = NodeEntry { id: node.clone(), endpoint: dest }; if !entry.endpoint.is_valid() { debug!(target: "discovery", "Bad address: {:?}", entry); @@ -402,10 +402,7 @@ impl Discovery { trace!(target: "discovery", "Got FindNode from {:?}", &from); let target: NodeId = try!(rlp.val_at(0)); let timestamp: u64 = try!(rlp.val_at(1)); - if timestamp < time::get_time().sec as u64 { - return Err(NetworkError::Expired); - } - + try!(self.check_timestamp(timestamp)); let limit = (MAX_DATAGRAM_SIZE - 109) / 90; let nearest = Discovery::nearest_node_entries(&target, &self.node_buckets); if nearest.is_empty() { @@ -504,6 +501,7 @@ mod tests { use network::node_table::*; use crypto::KeyPair; use std::str::FromStr; + use rustc_serialize::hex::FromHex; #[test] fn discovery() { @@ -543,7 +541,7 @@ mod tests { #[test] fn removes_expired() { let key = KeyPair::create().unwrap(); - let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40444 }; + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40447 }; let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0); for _ in 0..1200 { discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); @@ -552,4 +550,70 @@ mod tests { let removed = discovery.check_expired(true).len(); assert!(removed > 0); } + + #[test] + fn packets() { + let key = KeyPair::create().unwrap(); + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0); + discovery.check_timestamps = false; + let from = SocketAddr::from_str("99.99.99.99:40445").unwrap(); + + let packet = "\ + e9614ccfd9fc3e74360018522d30e1419a143407ffcce748de3e22116b7e8dc92ff74788c0b6663a\ + aa3d67d641936511c8f8d6ad8698b820a7cf9e1be7155e9a241f556658c55428ec0563514365799a\ + 4be2be5a685a80971ddcfa80cb422cdd0101ec04cb847f000001820cfa8215a8d790000000000000\ + 000000000000000000018208ae820d058443b9a3550102\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + 577be4349c4dd26768081f58de4c6f375a7a22f3f7adda654d1428637412c3d7fe917cadc56d4e5e\ + 7ffae1dbe3efffb9849feb71b262de37977e7c7a44e677295680e9e38ab26bee2fcbae207fba3ff3\ + d74069a50b902a82c9903ed37cc993c50001f83e82022bd79020010db83c4d001500000000abcdef\ + 12820cfa8215a8d79020010db885a308d313198a2e037073488208ae82823a8443b9a355c5010203\ + 040531b9019afde696e582a78fa8d95ea13ce3297d4afb8ba6433e4154caa5ac6431af1b80ba7602\ + 3fa4090c408f6b4bc3701562c031041d4702971d102c9ab7fa5eed4cd6bab8f7af956f7d565ee191\ + 7084a95398b6a21eac920fe3dd1345ec0a7ef39367ee69ddf092cbfe5b93e5e568ebc491983c09c7\ + 6d922dc3\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + 09b2428d83348d27cdf7064ad9024f526cebc19e4958f0fdad87c15eb598dd61d08423e0bf66b206\ + 9869e1724125f820d851c136684082774f870e614d95a2855d000f05d1648b2d5945470bc187c2d2\ + 216fbe870f43ed0909009882e176a46b0102f846d79020010db885a308d313198a2e037073488208\ + ae82823aa0fbc914b16819237dcd8801d7e53f69e9719adecb3cc0e790c57e91ca4461c9548443b9\ + a355c6010203c2040506a0c969a58f6f9095004c0177a6b47f451530cab38966a25cca5cb58f0555 + 42124e\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + c7c44041b9f7c7e41934417ebac9a8e1a4c6298f74553f2fcfdcae6ed6fe53163eb3d2b52e39fe91\ + 831b8a927bf4fc222c3902202027e5e9eb812195f95d20061ef5cd31d502e47ecb61183f74a504fe\ + 04c51e73df81f25c4d506b26db4517490103f84eb840ca634cae0d49acb401d8a4c6b6fe8c55b70d\ + 115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be0081290476\ + 7bf5ccd1fc7f8443b9a35582999983999999280dc62cc8255c73471e0a61da0c89acdc0e035e260a\ + dd7fc0c04ad9ebf3919644c91cb247affc82b69bd2ca235c71eab8e49737c937a2c396\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + c679fc8fe0b8b12f06577f2e802d34f6fa257e6137a995f6f4cbfc9ee50ed3710faf6e66f932c4c8\ + d81d64343f429651328758b47d3dbc02c4042f0fff6946a50f4a49037a72bb550f3a7872363a83e1\ + b9ee6469856c24eb4ef80b7535bcf99c0004f9015bf90150f84d846321163782115c82115db84031\ + 55e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa8291\ + 15d224c523596b401065a97f74010610fce76382c0bf32f84984010203040101b840312c55512422\ + cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e82\ + 9f04c2d314fc2d4e255e0d3bc08792b069dbf8599020010db83c4d001500000000abcdef12820d05\ + 820d05b84038643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2\ + d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aacf8599020010db885a308d3\ + 13198a2e037073488203e78203e8b8408dcab8618c3253b558d459da53bd8fa68935a719aff8b811\ + 197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73\ + 8443b9a355010203b525a138aa34383fec3d2719a0\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + } + } diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 087de63b3..30dd70c79 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -15,9 +15,11 @@ // along with Parity. If not, see . use std::sync::Arc; +use rand::random; use mio::*; use mio::tcp::*; use hash::*; +use rlp::*; use sha3::Hashable; use bytes::Bytes; use crypto::*; @@ -36,8 +38,12 @@ enum HandshakeState { New, /// Waiting for auth packet ReadingAuth, + /// Waiting for extended auth packet + ReadingAuthEip8, /// Waiting for ack packet ReadingAck, + /// Waiting for extended ack packet + ReadingAckEip8, /// Ready to start a session StartSession, } @@ -57,9 +63,11 @@ pub struct Handshake { /// Connection nonce pub nonce: H256, /// Handshake public key - pub remote_public: Public, + pub remote_ephemeral: Public, /// Remote connection nonce. pub remote_nonce: H256, + /// Remote RLPx protocol version. + pub remote_version: u64, /// A copy of received encryped auth packet pub auth_cipher: Bytes, /// A copy of received encryped ack packet @@ -68,9 +76,12 @@ pub struct Handshake { pub expired: bool, } -const AUTH_PACKET_SIZE: usize = 307; -const ACK_PACKET_SIZE: usize = 210; +const V4_AUTH_PACKET_SIZE: usize = 307; +const V4_ACK_PACKET_SIZE: usize = 210; const HANDSHAKE_TIMEOUT: u64 = 5000; +const PROTOCOL_VERSION: u64 = 4; +// Amount of bytes added when encrypting with encryptECIES. +const ECIES_OVERHEAD: usize = 113; impl Handshake { /// Create a new handshake object @@ -82,8 +93,9 @@ impl Handshake { state: HandshakeState::New, ecdhe: try!(KeyPair::create()), nonce: nonce.clone(), - remote_public: Public::new(), + remote_ephemeral: Public::new(), remote_nonce: H256::new(), + remote_version: PROTOCOL_VERSION, auth_cipher: Bytes::new(), ack_cipher: Bytes::new(), expired: false, @@ -115,11 +127,11 @@ impl Handshake { self.originated = originated; io.register_timer(self.connection.token, HANDSHAKE_TIMEOUT).ok(); if originated { - try!(self.write_auth(host)); + try!(self.write_auth(host.secret(), host.id())); } else { self.state = HandshakeState::ReadingAuth; - self.connection.expect(AUTH_PACKET_SIZE); + self.connection.expect(V4_AUTH_PACKET_SIZE); }; Ok(()) } @@ -134,20 +146,28 @@ impl Handshake { if !self.expired() { io.clear_timer(self.connection.token).unwrap(); match self.state { + HandshakeState::New => {} HandshakeState::ReadingAuth => { if let Some(data) = try!(self.connection.readable()) { - try!(self.read_auth(host, &data)); - try!(self.write_ack()); + try!(self.read_auth(host.secret(), &data)); + }; + }, + HandshakeState::ReadingAuthEip8 => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_auth_eip8(host.secret(), &data)); }; }, HandshakeState::ReadingAck => { if let Some(data) = try!(self.connection.readable()) { - try!(self.read_ack(host, &data)); - self.state = HandshakeState::StartSession; + try!(self.read_ack(host.secret(), &data)); + }; + }, + HandshakeState::ReadingAckEip8 => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_ack_eip8(host.secret(), &data)); }; }, HandshakeState::StartSession => {}, - _ => { panic!("Unexpected state"); } } if self.state != HandshakeState::StartSession { try!(io.update_registration(self.connection.token)); @@ -190,48 +210,105 @@ impl Handshake { Ok(()) } + fn set_auth(&mut self, host_secret: &Secret, sig: &[u8], remote_public: &[u8], remote_nonce: &[u8], remote_version: u64) -> Result<(), UtilError> { + self.id.clone_from_slice(remote_public); + self.remote_nonce.clone_from_slice(remote_nonce); + self.remote_version = remote_version; + let shared = try!(ecdh::agree(host_secret, &self.id)); + let signature = Signature::from_slice(sig); + self.remote_ephemeral = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce))); + Ok(()) + } + /// Parse, validate and confirm auth message - fn read_auth(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); - if data.len() != AUTH_PACKET_SIZE { + fn read_auth(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { + trace!(target:"net", "Received handshake auth from {:?}", self.connection.socket.peer_addr()); + if data.len() != V4_AUTH_PACKET_SIZE { debug!(target:"net", "Wrong auth packet size"); return Err(From::from(NetworkError::BadProtocol)); } self.auth_cipher = data.to_vec(); - let auth = try!(ecies::decrypt(host.secret(), data)); - let (sig, rest) = auth.split_at(65); - let (hepubk, rest) = rest.split_at(32); - let (pubk, rest) = rest.split_at(64); - let (nonce, _) = rest.split_at(32); - self.id.clone_from_slice(pubk); - self.remote_nonce.clone_from_slice(nonce); - let shared = try!(ecdh::agree(host.secret(), &self.id)); - let signature = Signature::from_slice(sig); - let spub = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce))); - self.remote_public = spub.clone(); - if &spub.sha3()[..] != hepubk { - trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr()); - return Err(From::from(NetworkError::Auth)); - }; + match ecies::decrypt(secret, &[], data) { + Ok(auth) => { + let (sig, rest) = auth.split_at(65); + let (_, rest) = rest.split_at(32); + let (pubk, rest) = rest.split_at(64); + let (nonce, _) = rest.split_at(32); + try!(self.set_auth(secret, sig, pubk, nonce, PROTOCOL_VERSION)); + try!(self.write_ack()); + } + Err(_) => { + // Try to interpret as EIP-8 packet + let size = ((data[0] as u16) << 8 | (data[1] as u16)) as usize; + if size < V4_AUTH_PACKET_SIZE - 2 { + debug!(target:"net", "Wrong EIP8 auth packet size"); + return Err(From::from(NetworkError::BadProtocol)); + } + let rest = size - data.len() + 2; + self.state = HandshakeState::ReadingAuthEip8; + self.connection.expect(rest); + } + } + Ok(()) + } + + fn read_auth_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { + trace!(target:"net", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + self.auth_cipher.extend_from_slice(data); + let auth = try!(ecies::decrypt(secret, &self.auth_cipher[0..2], &self.auth_cipher[2..])); + let rlp = UntrustedRlp::new(&auth); + let signature: Signature = try!(rlp.val_at(0)); + let remote_public: Public = try!(rlp.val_at(1)); + let remote_nonce: H256 = try!(rlp.val_at(2)); + let remote_version: u64 = try!(rlp.val_at(3)); + try!(self.set_auth(secret, &signature, &remote_public, &remote_nonce, remote_version)); + try!(self.write_ack_eip8()); Ok(()) } /// Parse and validate ack message - fn read_ack(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> { + fn read_ack(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); - if data.len() != ACK_PACKET_SIZE { + if data.len() != V4_ACK_PACKET_SIZE { debug!(target:"net", "Wrong ack packet size"); return Err(From::from(NetworkError::BadProtocol)); } self.ack_cipher = data.to_vec(); - let ack = try!(ecies::decrypt(host.secret(), data)); - self.remote_public.clone_from_slice(&ack[0..64]); - self.remote_nonce.clone_from_slice(&ack[64..(64+32)]); + match ecies::decrypt(secret, &[], data) { + Ok(ack) => { + self.remote_ephemeral.clone_from_slice(&ack[0..64]); + self.remote_nonce.clone_from_slice(&ack[64..(64+32)]); + self.state = HandshakeState::StartSession; + } + Err(_) => { + // Try to interpret as EIP-8 packet + let size = ((data[0] as u16) << 8 | (data[1] as u16)) as usize; + if size < (V4_ACK_PACKET_SIZE - 2) { + debug!(target:"net", "Wrong EIP8 ack packet size"); + return Err(From::from(NetworkError::BadProtocol)); + } + let rest = size - data.len() + 2; + self.state = HandshakeState::ReadingAckEip8; + self.connection.expect(rest); + } + } + Ok(()) + } + + fn read_ack_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { + trace!(target:"net", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + self.ack_cipher.extend_from_slice(data); + let ack = try!(ecies::decrypt(secret, &self.ack_cipher[0..2], &self.ack_cipher[2..])); + let rlp = UntrustedRlp::new(&ack); + self.remote_ephemeral = try!(rlp.val_at(0)); + self.remote_nonce = try!(rlp.val_at(1)); + self.remote_version = try!(rlp.val_at(2)); + self.state = HandshakeState::StartSession; Ok(()) } /// Sends auth message - fn write_auth(&mut self, host: &HostInfo) -> Result<(), UtilError> { + fn write_auth(&mut self, secret: &Secret, public: &Public) -> Result<(), UtilError> { trace!(target:"net", "Sending handshake auth to {:?}", self.connection.socket.peer_addr()); let mut data = [0u8; /*Signature::SIZE*/ 65 + /*H256::SIZE*/ 32 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32 + 1]; //TODO: use associated constants let len = data.len(); @@ -243,16 +320,16 @@ impl Handshake { let (nonce, _) = rest.split_at_mut(32); // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) - let shared = try!(crypto::ecdh::agree(host.secret(), &self.id)); + let shared = try!(crypto::ecdh::agree(secret, &self.id)); try!(crypto::ec::sign(self.ecdhe.secret(), &(&shared ^ &self.nonce))).copy_to(sig); self.ecdhe.public().sha3_into(hepubk); - host.id().copy_to(pubk); + public.copy_to(pubk); self.nonce.copy_to(nonce); } - let message = try!(crypto::ecies::encrypt(&self.id, &data)); + let message = try!(crypto::ecies::encrypt(&self.id, &[], &data)); self.auth_cipher = message.clone(); self.connection.send(message); - self.connection.expect(ACK_PACKET_SIZE); + self.connection.expect(V4_ACK_PACKET_SIZE); self.state = HandshakeState::ReadingAck; Ok(()) } @@ -269,10 +346,219 @@ impl Handshake { self.ecdhe.public().copy_to(epubk); self.nonce.copy_to(nonce); } - let message = try!(crypto::ecies::encrypt(&self.id, &data)); + let message = try!(crypto::ecies::encrypt(&self.id, &[], &data)); self.ack_cipher = message.clone(); self.connection.send(message); self.state = HandshakeState::StartSession; Ok(()) } + + /// Sends EIP8 ack message + fn write_ack_eip8(&mut self) -> Result<(), UtilError> { + trace!(target:"net", "Sending EIP8 handshake ack to {:?}", self.connection.socket.peer_addr()); + let mut rlp = RlpStream::new_list(3); + rlp.append(self.ecdhe.public()); + rlp.append(&self.nonce); + rlp.append(&PROTOCOL_VERSION); + + let pad_array = [0u8; 200]; + let pad = &pad_array[0 .. 100 + random::() % 100]; + rlp.append_raw(pad, 0); + + let encoded = rlp.drain(); + let len = (encoded.len() + ECIES_OVERHEAD) as u16; + let prefix = [ (len & 0xff) as u8, (len >> 8) as u8 ]; + let message = try!(crypto::ecies::encrypt(&self.id, &prefix, &encoded)); + self.ack_cipher.extend_from_slice(&prefix); + self.ack_cipher.extend_from_slice(&message); + self.connection.send(self.ack_cipher.clone()); + self.state = HandshakeState::StartSession; + Ok(()) + } } + +#[cfg(test)] +mod test { + use std::sync::Arc; + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use super::*; + use crypto::*; + use hash::*; + use std::net::SocketAddr; + use mio::tcp::TcpStream; + use network::stats::NetworkStats; + + fn check_auth(h: &Handshake, version: u64) { + assert_eq!(h.id, Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap()); + assert_eq!(h.remote_nonce, H256::from_str("7e968bba13b6c50e2c4cd7f241cc0d64d1ac25c7f5952df231ac6a2bda8ee5d6").unwrap()); + assert_eq!(h.remote_ephemeral, Public::from_str("654d1044b69c577a44e5f01a1209523adb4026e70c62d1c13a067acabc09d2667a49821a0ad4b634554d330a15a58fe61f8a8e0544b310c6de7b0c8da7528a8d").unwrap()); + assert_eq!(h.remote_version, version); + } + + fn check_ack(h: &Handshake, version: u64) { + assert_eq!(h.remote_nonce, H256::from_str("559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd").unwrap()); + assert_eq!(h.remote_ephemeral, Public::from_str("b6d82fa3409da933dbf9cb0140c5dde89f4e64aec88d476af648880f4a10e1e49fe35ef3e69e93dd300b4797765a747c6384a6ecf5db9c2690398607a86181e4").unwrap()); + assert_eq!(h.remote_version, version); + } + + fn create_handshake(to: Option<&Public>) -> Handshake { + let addr = SocketAddr::from_str("127.0.0.1:50556").unwrap(); + let socket = TcpStream::connect(&addr).unwrap(); + let nonce = H256::new(); + Handshake::new(0, to, socket, &nonce, Arc::new(NetworkStats::new())).unwrap() + } + + #[test] + fn test_handshake_auth_plain() { + let mut h = create_handshake(None); + let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); + let auth = + "\ + 048ca79ad18e4b0659fab4853fe5bc58eb83992980f4c9cc147d2aa31532efd29a3d3dc6a3d89eaf\ + 913150cfc777ce0ce4af2758bf4810235f6e6ceccfee1acc6b22c005e9e3a49d6448610a58e98744\ + ba3ac0399e82692d67c1f58849050b3024e21a52c9d3b01d871ff5f210817912773e610443a9ef14\ + 2e91cdba0bd77b5fdf0769b05671fc35f83d83e4d3b0b000c6b2a1b1bba89e0fc51bf4e460df3105\ + c444f14be226458940d6061c296350937ffd5e3acaceeaaefd3c6f74be8e23e0f45163cc7ebd7622\ + 0f0128410fd05250273156d548a414444ae2f7dea4dfca2d43c057adb701a715bf59f6fb66b2d1d2\ + 0f2c703f851cbf5ac47396d9ca65b6260bd141ac4d53e2de585a73d1750780db4c9ee4cd4d225173\ + a4592ee77e2bd94d0be3691f3b406f9bba9b591fc63facc016bfa8\ + ".from_hex().unwrap(); + + h.read_auth(&secret, &auth).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_auth(&h, 4); + } + + #[test] + fn test_handshake_auth_eip8() { + let mut h = create_handshake(None); + let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); + let auth = + "\ + 01b304ab7578555167be8154d5cc456f567d5ba302662433674222360f08d5f1534499d3678b513b\ + 0fca474f3a514b18e75683032eb63fccb16c156dc6eb2c0b1593f0d84ac74f6e475f1b8d56116b84\ + 9634a8c458705bf83a626ea0384d4d7341aae591fae42ce6bd5c850bfe0b999a694a49bbbaf3ef6c\ + da61110601d3b4c02ab6c30437257a6e0117792631a4b47c1d52fc0f8f89caadeb7d02770bf999cc\ + 147d2df3b62e1ffb2c9d8c125a3984865356266bca11ce7d3a688663a51d82defaa8aad69da39ab6\ + d5470e81ec5f2a7a47fb865ff7cca21516f9299a07b1bc63ba56c7a1a892112841ca44b6e0034dee\ + 70c9adabc15d76a54f443593fafdc3b27af8059703f88928e199cb122362a4b35f62386da7caad09\ + c001edaeb5f8a06d2b26fb6cb93c52a9fca51853b68193916982358fe1e5369e249875bb8d0d0ec3\ + 6f917bc5e1eafd5896d46bd61ff23f1a863a8a8dcd54c7b109b771c8e61ec9c8908c733c0263440e\ + 2aa067241aaa433f0bb053c7b31a838504b148f570c0ad62837129e547678c5190341e4f1693956c\ + 3bf7678318e2d5b5340c9e488eefea198576344afbdf66db5f51204a6961a63ce072c8926c\ + ".from_hex().unwrap(); + + h.read_auth(&secret, &auth[0..super::V4_AUTH_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAuthEip8); + h.read_auth_eip8(&secret, &auth[super::V4_AUTH_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_auth(&h, 4); + } + + #[test] + fn test_handshake_auth_eip8_2() { + let mut h = create_handshake(None); + let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); + let auth = + "\ + 01b8044c6c312173685d1edd268aa95e1d495474c6959bcdd10067ba4c9013df9e40ff45f5bfd6f7\ + 2471f93a91b493f8e00abc4b80f682973de715d77ba3a005a242eb859f9a211d93a347fa64b597bf\ + 280a6b88e26299cf263b01b8dfdb712278464fd1c25840b995e84d367d743f66c0e54a586725b7bb\ + f12acca27170ae3283c1073adda4b6d79f27656993aefccf16e0d0409fe07db2dc398a1b7e8ee93b\ + cd181485fd332f381d6a050fba4c7641a5112ac1b0b61168d20f01b479e19adf7fdbfa0905f63352\ + bfc7e23cf3357657455119d879c78d3cf8c8c06375f3f7d4861aa02a122467e069acaf513025ff19\ + 6641f6d2810ce493f51bee9c966b15c5043505350392b57645385a18c78f14669cc4d960446c1757\ + 1b7c5d725021babbcd786957f3d17089c084907bda22c2b2675b4378b114c601d858802a55345a15\ + 116bc61da4193996187ed70d16730e9ae6b3bb8787ebcaea1871d850997ddc08b4f4ea668fbf3740\ + 7ac044b55be0908ecb94d4ed172ece66fd31bfdadf2b97a8bc690163ee11f5b575a4b44e36e2bfb2\ + f0fce91676fd64c7773bac6a003f481fddd0bae0a1f31aa27504e2a533af4cef3b623f4791b2cca6\ + d490\ + ".from_hex().unwrap(); + + h.read_auth(&secret, &auth[0..super::V4_AUTH_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAuthEip8); + h.read_auth_eip8(&secret, &auth[super::V4_AUTH_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_auth(&h, 56); + } + + #[test] + fn test_handshake_ack_plain() { + let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); + let mut h = create_handshake(Some(&remote)); + let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); + let ack = + "\ + 049f8abcfa9c0dc65b982e98af921bc0ba6e4243169348a236abe9df5f93aa69d99cadddaa387662\ + b0ff2c08e9006d5a11a278b1b3331e5aaabf0a32f01281b6f4ede0e09a2d5f585b26513cb794d963\ + 5a57563921c04a9090b4f14ee42be1a5461049af4ea7a7f49bf4c97a352d39c8d02ee4acc416388c\ + 1c66cec761d2bc1c72da6ba143477f049c9d2dde846c252c111b904f630ac98e51609b3b1f58168d\ + dca6505b7196532e5f85b259a20c45e1979491683fee108e9660edbf38f3add489ae73e3dda2c71b\ + d1497113d5c755e942d1\ + ".from_hex().unwrap(); + + h.read_ack(&secret, &ack).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_ack(&h, 4); + } + + #[test] + fn test_handshake_ack_eip8() { + let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); + let mut h = create_handshake(Some(&remote)); + let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); + let ack = + "\ + 01ea0451958701280a56482929d3b0757da8f7fbe5286784beead59d95089c217c9b917788989470\ + b0e330cc6e4fb383c0340ed85fab836ec9fb8a49672712aeabbdfd1e837c1ff4cace34311cd7f4de\ + 05d59279e3524ab26ef753a0095637ac88f2b499b9914b5f64e143eae548a1066e14cd2f4bd7f814\ + c4652f11b254f8a2d0191e2f5546fae6055694aed14d906df79ad3b407d94692694e259191cde171\ + ad542fc588fa2b7333313d82a9f887332f1dfc36cea03f831cb9a23fea05b33deb999e85489e645f\ + 6aab1872475d488d7bd6c7c120caf28dbfc5d6833888155ed69d34dbdc39c1f299be1057810f34fb\ + e754d021bfca14dc989753d61c413d261934e1a9c67ee060a25eefb54e81a4d14baff922180c395d\ + 3f998d70f46f6b58306f969627ae364497e73fc27f6d17ae45a413d322cb8814276be6ddd13b885b\ + 201b943213656cde498fa0e9ddc8e0b8f8a53824fbd82254f3e2c17e8eaea009c38b4aa0a3f306e8\ + 797db43c25d68e86f262e564086f59a2fc60511c42abfb3057c247a8a8fe4fb3ccbadde17514b7ac\ + 8000cdb6a912778426260c47f38919a91f25f4b5ffb455d6aaaf150f7e5529c100ce62d6d92826a7\ + 1778d809bdf60232ae21ce8a437eca8223f45ac37f6487452ce626f549b3b5fdee26afd2072e4bc7\ + 5833c2464c805246155289f4\ + ".from_hex().unwrap(); + + h.read_ack(&secret, &ack[0..super::V4_ACK_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAckEip8); + h.read_ack_eip8(&secret, &ack[super::V4_ACK_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_ack(&h, 4); + } + + #[test] + fn test_handshake_ack_eip8_2() { + let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); + let mut h = create_handshake(Some(&remote)); + let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); + let ack = + "\ + 01f004076e58aae772bb101ab1a8e64e01ee96e64857ce82b1113817c6cdd52c09d26f7b90981cd7\ + ae835aeac72e1573b8a0225dd56d157a010846d888dac7464baf53f2ad4e3d584531fa203658fab0\ + 3a06c9fd5e35737e417bc28c1cbf5e5dfc666de7090f69c3b29754725f84f75382891c561040ea1d\ + dc0d8f381ed1b9d0d4ad2a0ec021421d847820d6fa0ba66eaf58175f1b235e851c7e2124069fbc20\ + 2888ddb3ac4d56bcbd1b9b7eab59e78f2e2d400905050f4a92dec1c4bdf797b3fc9b2f8e84a482f3\ + d800386186712dae00d5c386ec9387a5e9c9a1aca5a573ca91082c7d68421f388e79127a5177d4f8\ + 590237364fd348c9611fa39f78dcdceee3f390f07991b7b47e1daa3ebcb6ccc9607811cb17ce51f1\ + c8c2c5098dbdd28fca547b3f58c01a424ac05f869f49c6a34672ea2cbbc558428aa1fe48bbfd6115\ + 8b1b735a65d99f21e70dbc020bfdface9f724a0d1fb5895db971cc81aa7608baa0920abb0a565c9c\ + 436e2fd13323428296c86385f2384e408a31e104670df0791d93e743a3a5194ee6b076fb6323ca59\ + 3011b7348c16cf58f66b9633906ba54a2ee803187344b394f75dd2e663a57b956cb830dd7a908d4f\ + 39a2336a61ef9fda549180d4ccde21514d117b6c6fd07a9102b5efe710a32af4eeacae2cb3b1dec0\ + 35b9593b48b9d3ca4c13d245d5f04169b0b1\ + ".from_hex().unwrap(); + + h.read_ack(&secret, &ack[0..super::V4_ACK_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAckEip8); + h.read_ack_eip8(&secret, &ack[super::V4_ACK_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_ack(&h, 57); + } +} + From c8076b2f9d9ac45e1a431366eaa5710cedfdcccc Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 21 Feb 2016 19:46:29 +0100 Subject: [PATCH 174/753] Threading performance optimizations --- Cargo.lock | 3 +- Cargo.toml | 3 + ethcore/src/block_queue.rs | 146 +++++++++++++++++++----------------- ethcore/src/client.rs | 30 ++++---- ethcore/src/verification.rs | 14 +--- util/sha3/build.rs | 2 +- util/src/lib.rs | 2 + util/src/thread.rs | 43 +++++++++++ 8 files changed, 148 insertions(+), 95 deletions(-) create mode 100644 util/src/thread.rs diff --git a/Cargo.lock b/Cargo.lock index cf747f3cc..50274857f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,7 +151,6 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.4" -source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -223,7 +222,7 @@ dependencies = [ "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", + "eth-secp256k1 0.5.4", "ethcore-devtools 0.9.99", "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 7fdfc2bee..f28829180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,6 @@ travis-nightly = ["ethcore/json-tests", "dev"] [[bin]] path = "parity/main.rs" name = "parity" + +[profile.release] +debug = true diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index c39f158f0..a51a1e900 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -63,7 +63,7 @@ pub struct BlockQueue { panic_handler: Arc, engine: Arc>, more_to_verify: Arc, - verification: Arc>, + verification: Arc, verifiers: Vec>, deleting: Arc, ready_signal: Arc, @@ -98,12 +98,11 @@ impl QueueSignal { } } -#[derive(Default)] struct Verification { - unverified: VecDeque, - verified: VecDeque, - verifying: VecDeque, - bad: HashSet, + unverified: Mutex>, + verified: Mutex>, + verifying: Mutex>, + bad: Mutex>, } const MAX_UNVERIFIED_QUEUE_SIZE: usize = 50000; @@ -111,7 +110,12 @@ const MAX_UNVERIFIED_QUEUE_SIZE: usize = 50000; impl BlockQueue { /// Creates a new queue instance. pub fn new(engine: Arc>, message_channel: IoChannel) -> BlockQueue { - let verification = Arc::new(Mutex::new(Verification::default())); + let verification = Arc::new(Verification { + unverified: Mutex::new(VecDeque::new()), + verified: Mutex::new(VecDeque::new()), + verifying: Mutex::new(VecDeque::new()), + bad: Mutex::new(HashSet::new()), + }); let more_to_verify = Arc::new(Condvar::new()); let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel }); let deleting = Arc::new(AtomicBool::new(false)); @@ -119,7 +123,7 @@ impl BlockQueue { let panic_handler = PanicHandler::new_in_arc(); let mut verifiers: Vec> = Vec::new(); - let thread_count = max(::num_cpus::get(), 3) - 2; + let thread_count = max(::num_cpus::get(), 5) - 0; for i in 0..thread_count { let verification = verification.clone(); let engine = engine.clone(); @@ -133,7 +137,8 @@ impl BlockQueue { .name(format!("Verifier #{}", i)) .spawn(move || { panic_handler.catch_panic(move || { - BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) + lower_thread_priority(); + BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) }).unwrap() }) .expect("Error starting block verification thread") @@ -152,17 +157,17 @@ impl BlockQueue { } } - fn verify(verification: Arc>, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { + fn verify(verification: Arc, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { while !deleting.load(AtomicOrdering::Acquire) { { - let mut lock = verification.lock().unwrap(); + let mut unverified = verification.unverified.lock().unwrap(); - if lock.unverified.is_empty() && lock.verifying.is_empty() { + if unverified.is_empty() && verification.verifying.lock().unwrap().is_empty() { empty.notify_all(); } - while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) { - lock = wait.wait(lock).unwrap(); + while unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) { + unverified = wait.wait(unverified).unwrap(); } if deleting.load(AtomicOrdering::Acquire) { @@ -171,39 +176,42 @@ impl BlockQueue { } let block = { - let mut v = verification.lock().unwrap(); - if v.unverified.is_empty() { + let mut unverified = verification.unverified.lock().unwrap(); + if unverified.is_empty() { continue; } - let block = v.unverified.pop_front().unwrap(); - v.verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None }); + let mut verifying = verification.verifying.lock().unwrap(); + let block = unverified.pop_front().unwrap(); + verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None }); block }; let block_hash = block.header.hash(); match verify_block_unordered(block.header, block.bytes, engine.deref().deref()) { Ok(verified) => { - let mut v = verification.lock().unwrap(); - for e in &mut v.verifying { + let mut verifying = verification.verifying.lock().unwrap(); + for e in verifying.iter_mut() { if e.hash == block_hash { e.block = Some(verified); break; } } - if !v.verifying.is_empty() && v.verifying.front().unwrap().hash == block_hash { + if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash { // we're next! - let mut vref = v.deref_mut(); - BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad); + let mut verified = verification.verified.lock().unwrap(); + let mut bad = verification.bad.lock().unwrap(); + BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad); ready.set(); } }, Err(err) => { - let mut v = verification.lock().unwrap(); + let mut verifying = verification.verifying.lock().unwrap(); + let mut verified = verification.verified.lock().unwrap(); + let mut bad = verification.bad.lock().unwrap(); warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); - v.bad.insert(block_hash.clone()); - v.verifying.retain(|e| e.hash != block_hash); - let mut vref = v.deref_mut(); - BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad); + bad.insert(block_hash.clone()); + verifying.retain(|e| e.hash != block_hash); + BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad); ready.set(); } } @@ -223,19 +231,21 @@ impl BlockQueue { } /// Clear the queue and stop verification activity. - pub fn clear(&mut self) { - let mut verification = self.verification.lock().unwrap(); - verification.unverified.clear(); - verification.verifying.clear(); - verification.verified.clear(); + pub fn clear(&self) { + let mut unverified = self.verification.unverified.lock().unwrap(); + let mut verifying = self.verification.verifying.lock().unwrap(); + let mut verified = self.verification.verified.lock().unwrap(); + unverified.clear(); + verifying.clear(); + verified.clear(); self.processing.write().unwrap().clear(); } - /// Wait for queue to be empty - pub fn flush(&mut self) { - let mut verification = self.verification.lock().unwrap(); - while !verification.unverified.is_empty() || !verification.verifying.is_empty() { - verification = self.empty.wait(verification).unwrap(); + /// Wait for unverified queue to be empty + pub fn flush(&self) { + let mut unverified = self.verification.unverified.lock().unwrap(); + while !unverified.is_empty() || !self.verification.verifying.lock().unwrap().is_empty() { + unverified = self.empty.wait(unverified).unwrap(); } } @@ -244,27 +254,29 @@ impl BlockQueue { if self.processing.read().unwrap().contains(&hash) { return BlockStatus::Queued; } - if self.verification.lock().unwrap().bad.contains(&hash) { + if self.verification.bad.lock().unwrap().contains(&hash) { return BlockStatus::Bad; } BlockStatus::Unknown } /// Add a block to the queue. - pub fn import_block(&mut self, bytes: Bytes) -> ImportResult { + pub fn import_block(&self, bytes: Bytes) -> ImportResult { let header = BlockView::new(&bytes).header(); let h = header.hash(); - if self.processing.read().unwrap().contains(&h) { - return Err(ImportError::AlreadyQueued); - } { - let mut verification = self.verification.lock().unwrap(); - if verification.bad.contains(&h) { + if self.processing.read().unwrap().contains(&h) { + return Err(ImportError::AlreadyQueued); + } + } + { + let mut bad = self.verification.bad.lock().unwrap(); + if bad.contains(&h) { return Err(ImportError::Bad(None)); } - if verification.bad.contains(&header.parent_hash) { - verification.bad.insert(h.clone()); + if bad.contains(&header.parent_hash) { + bad.insert(h.clone()); return Err(ImportError::Bad(None)); } } @@ -272,39 +284,40 @@ impl BlockQueue { match verify_block_basic(&header, &bytes, self.engine.deref().deref()) { Ok(()) => { self.processing.write().unwrap().insert(h.clone()); - self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes }); + self.verification.unverified.lock().unwrap().push_back(UnVerifiedBlock { header: header, bytes: bytes }); self.more_to_verify.notify_all(); Ok(h) }, Err(err) => { warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); - self.verification.lock().unwrap().bad.insert(h.clone()); + self.verification.bad.lock().unwrap().insert(h.clone()); Err(From::from(err)) } } } /// Mark given block and all its children as bad. Stops verification. - pub fn mark_as_bad(&mut self, hash: &H256) { - let mut verification_lock = self.verification.lock().unwrap(); - let mut verification = verification_lock.deref_mut(); - verification.bad.insert(hash.clone()); + pub fn mark_as_bad(&self, hash: &H256) { + let mut verified_lock = self.verification.verified.lock().unwrap(); + let mut verified = verified_lock.deref_mut(); + let mut bad = self.verification.bad.lock().unwrap(); + bad.insert(hash.clone()); self.processing.write().unwrap().remove(&hash); let mut new_verified = VecDeque::new(); - for block in verification.verified.drain(..) { - if verification.bad.contains(&block.header.parent_hash) { - verification.bad.insert(block.header.hash()); + for block in verified.drain(..) { + if bad.contains(&block.header.parent_hash) { + bad.insert(block.header.hash()); self.processing.write().unwrap().remove(&block.header.hash()); } else { new_verified.push_back(block); } } - verification.verified = new_verified; + *verified = new_verified; } /// Mark given block as processed - pub fn mark_as_good(&mut self, hashes: &[H256]) { + pub fn mark_as_good(&self, hashes: &[H256]) { let mut processing = self.processing.write().unwrap(); for h in hashes { processing.remove(&h); @@ -312,16 +325,16 @@ impl BlockQueue { } /// Removes up to `max` verified blocks from the queue - pub fn drain(&mut self, max: usize) -> Vec { - let mut verification = self.verification.lock().unwrap(); - let count = min(max, verification.verified.len()); + pub fn drain(&self, max: usize) -> Vec { + let mut verified = self.verification.verified.lock().unwrap(); + let count = min(max, verified.len()); let mut result = Vec::with_capacity(count); for _ in 0..count { - let block = verification.verified.pop_front().unwrap(); + let block = verified.pop_front().unwrap(); result.push(block); } self.ready_signal.reset(); - if !verification.verified.is_empty() { + if !verified.is_empty() { self.ready_signal.set(); } result @@ -329,11 +342,10 @@ impl BlockQueue { /// Get queue status. pub fn queue_info(&self) -> BlockQueueInfo { - let verification = self.verification.lock().unwrap(); BlockQueueInfo { - verified_queue_size: verification.verified.len(), - unverified_queue_size: verification.unverified.len(), - verifying_queue_size: verification.verifying.len(), + unverified_queue_size: self.verification.unverified.lock().unwrap().len(), + verifying_queue_size: self.verification.verifying.lock().unwrap().len(), + verified_queue_size: self.verification.verified.lock().unwrap().len(), } } } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c3ec4b4d0..0c8580117 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -172,7 +172,7 @@ pub struct Client { chain: Arc>, engine: Arc>, state_db: Mutex, - block_queue: RwLock, + block_queue: BlockQueue, report: RwLock, import_lock: Mutex<()>, panic_handler: Arc, @@ -231,7 +231,7 @@ impl Client { chain: chain, engine: engine, state_db: Mutex::new(state_db), - block_queue: RwLock::new(block_queue), + block_queue: block_queue, report: RwLock::new(Default::default()), import_lock: Mutex::new(()), panic_handler: panic_handler @@ -240,7 +240,7 @@ impl Client { /// Flush the block import queue. pub fn flush_queue(&self) { - self.block_queue.write().unwrap().flush(); + self.block_queue.flush(); } /// This is triggered by a message coming from a block queue when the block is ready for insertion @@ -248,11 +248,11 @@ impl Client { let mut ret = 0; let mut bad = HashSet::new(); let _import_lock = self.import_lock.lock(); - let blocks = self.block_queue.write().unwrap().drain(128); + let blocks = self.block_queue.drain(128); let mut good_blocks = Vec::with_capacity(128); for block in blocks { if bad.contains(&block.header.parent_hash) { - self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); + self.block_queue.mark_as_bad(&block.header.hash()); bad.insert(block.header.hash()); continue; } @@ -260,7 +260,7 @@ impl Client { let header = &block.header; if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); bad.insert(block.header.hash()); break; }; @@ -268,7 +268,7 @@ impl Client { Some(p) => p, None => { warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); bad.insert(block.header.hash()); break; }, @@ -292,13 +292,13 @@ impl Client { Err(e) => { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); bad.insert(block.header.hash()); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); break; } }; if let Err(e) = verify_block_final(&header, result.block().header()) { warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); break; } @@ -317,8 +317,8 @@ impl Client { trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); ret += 1; } - self.block_queue.write().unwrap().mark_as_good(&good_blocks); - if !good_blocks.is_empty() && self.block_queue.read().unwrap().queue_info().is_empty() { + self.block_queue.mark_as_good(&good_blocks); + if !good_blocks.is_empty() && self.block_queue.queue_info().is_empty() { io.send(NetworkIoMessage::User(SyncMessage::BlockVerified)).unwrap(); } ret @@ -389,7 +389,7 @@ impl BlockChainClient for Client { let chain = self.chain.read().unwrap(); match Self::block_hash(&chain, id) { Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain, - Some(hash) => self.block_queue.read().unwrap().block_status(&hash), + Some(hash) => self.block_queue.block_status(&hash), None => BlockStatus::Unknown } } @@ -434,15 +434,15 @@ impl BlockChainClient for Client { if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { return Err(ImportError::UnknownParent); } - self.block_queue.write().unwrap().import_block(bytes) + self.block_queue.import_block(bytes) } fn queue_info(&self) -> BlockQueueInfo { - self.block_queue.read().unwrap().queue_info() + self.block_queue.queue_info() } fn clear_queue(&self) { - self.block_queue.write().unwrap().clear(); + self.block_queue.clear(); } fn chain_info(&self) -> BlockChainInfo { diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index c7d5e265f..fa9467e95 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -57,18 +57,12 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Still operates on a individual block /// Returns a PreVerifiedBlock structure populated with transactions pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { - try!(engine.verify_block_unordered(&header, Some(&bytes))); - for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { - try!(engine.verify_block_unordered(&u, None)); - } // Verify transactions. let mut transactions = Vec::new(); - { - let v = BlockView::new(&bytes); - for t in v.transactions() { - try!(engine.verify_transaction(&t, &header)); - transactions.push(t); - } + let v = BlockView::new(&bytes); + for t in v.transactions() { + try!(engine.verify_transaction(&t, &header)); + transactions.push(t); } Ok(PreVerifiedBlock { header: header, diff --git a/util/sha3/build.rs b/util/sha3/build.rs index bbe16d720..9eb36fdb9 100644 --- a/util/sha3/build.rs +++ b/util/sha3/build.rs @@ -21,6 +21,6 @@ extern crate gcc; fn main() { - gcc::compile_library("libtinykeccak.a", &["src/tinykeccak.c"]); + gcc::Config::new().file("src/tinykeccak.c").flag("-O3").compile("libtinykeccak.a"); } diff --git a/util/src/lib.rs b/util/src/lib.rs index 2b7438cf3..5c8bd4fb0 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -143,6 +143,7 @@ pub mod network; pub mod log; pub mod panics; pub mod keys; +mod thread; pub use common::*; pub use misc::*; @@ -163,4 +164,5 @@ pub use semantic_version::*; pub use network::*; pub use io::*; pub use log::*; +pub use thread::*; diff --git a/util/src/thread.rs b/util/src/thread.rs new file mode 100644 index 000000000..b86ca3e86 --- /dev/null +++ b/util/src/thread.rs @@ -0,0 +1,43 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Thread management helpers + +use libc::{c_int, pthread_self, pthread_t}; + +#[repr(C)] +struct sched_param { + priority: c_int, + padding: c_int, +} + +extern { + fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int; + fn pthread_setschedparam(thread: pthread_t, policy: c_int, param: *const sched_param) -> c_int; +} +const PRIO_DARWIN_THREAD: c_int = 3; +const PRIO_DARWIN_BG: c_int = 0x1000; +const SCHED_RR: c_int = 2; + +/// Lower thread priority and put it into background mode +#[cfg(target_os="macos")] +pub fn lower_thread_priority() { + let sp = sched_param { priority: 0, padding: 0 }; + if unsafe { pthread_setschedparam(pthread_self(), SCHED_RR, &sp) } == -1 { + trace!("Could not decrease thread piority"); + } + //unsafe { setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); } +} From 778fa92ebe82bcf7c739b4750a5443f2ed575802 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 22 Feb 2016 00:36:59 +0100 Subject: [PATCH 175/753] Remove locks from the block chain --- Cargo.lock | 3 +- Cargo.toml | 2 +- ethcore/src/block_queue.rs | 12 +++---- ethcore/src/blockchain.rs | 48 ++++++++++++++++------------ ethcore/src/client.rs | 63 +++++++++++++++++-------------------- ethcore/src/verification.rs | 14 ++++++--- util/src/lib.rs | 2 -- util/src/thread.rs | 43 ------------------------- 8 files changed, 75 insertions(+), 112 deletions(-) delete mode 100644 util/src/thread.rs diff --git a/Cargo.lock b/Cargo.lock index 50274857f..cf747f3cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,6 +151,7 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.4" +source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -222,7 +223,7 @@ dependencies = [ "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "eth-secp256k1 0.5.4", + "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", "ethcore-devtools 0.9.99", "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index f28829180..8bc94a3a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,4 +32,4 @@ path = "parity/main.rs" name = "parity" [profile.release] -debug = true +debug = false diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index a51a1e900..ba9867966 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -99,6 +99,7 @@ impl QueueSignal { } struct Verification { + // All locks must be captured in the order declared here. unverified: Mutex>, verified: Mutex>, verifying: Mutex>, @@ -123,7 +124,7 @@ impl BlockQueue { let panic_handler = PanicHandler::new_in_arc(); let mut verifiers: Vec> = Vec::new(); - let thread_count = max(::num_cpus::get(), 5) - 0; + let thread_count = max(::num_cpus::get(), 3) - 2; for i in 0..thread_count { let verification = verification.clone(); let engine = engine.clone(); @@ -137,7 +138,6 @@ impl BlockQueue { .name(format!("Verifier #{}", i)) .spawn(move || { panic_handler.catch_panic(move || { - lower_thread_priority(); BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) }).unwrap() }) @@ -392,7 +392,7 @@ mod tests { #[test] fn can_import_blocks() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); if let Err(e) = queue.import_block(get_good_dummy_block()) { panic!("error importing block that is valid by definition({:?})", e); } @@ -400,7 +400,7 @@ mod tests { #[test] fn returns_error_for_duplicates() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); if let Err(e) = queue.import_block(get_good_dummy_block()) { panic!("error importing block that is valid by definition({:?})", e); } @@ -419,7 +419,7 @@ mod tests { #[test] fn returns_ok_for_drained_duplicates() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); let block = get_good_dummy_block(); let hash = BlockView::new(&block).header().hash().clone(); if let Err(e) = queue.import_block(block) { @@ -436,7 +436,7 @@ mod tests { #[test] fn returns_empty_once_finished() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); queue.import_block(get_good_dummy_block()).expect("error importing block that is valid by definition"); queue.flush(); queue.drain(1); diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index cc9ff56fd..22d409e8e 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -16,6 +16,7 @@ //! Blockchain database. +use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; use util::*; use rocksdb::{DB, WriteBatch, Writable}; use header::*; @@ -147,8 +148,9 @@ struct CacheManager { /// /// **Does not do input data verification.** pub struct BlockChain { - pref_cache_size: usize, - max_cache_size: usize, + // All locks must be captured in the order declared here. + pref_cache_size: AtomicUsize, + max_cache_size: AtomicUsize, best_block: RwLock, @@ -166,6 +168,7 @@ pub struct BlockChain { blocks_db: DB, cache_man: RwLock, + insert_lock: Mutex<()> } impl BlockProvider for BlockChain { @@ -261,8 +264,8 @@ impl BlockChain { (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new())); let bc = BlockChain { - pref_cache_size: 1 << 14, - max_cache_size: 1 << 20, + pref_cache_size: AtomicUsize::new(1 << 14), + max_cache_size: AtomicUsize::new(1 << 20), best_block: RwLock::new(BestBlock::new()), blocks: RwLock::new(HashMap::new()), block_details: RwLock::new(HashMap::new()), @@ -273,6 +276,7 @@ impl BlockChain { extras_db: extras_db, blocks_db: blocks_db, cache_man: RwLock::new(cache_man), + insert_lock: Mutex::new(()), }; // load best block @@ -315,9 +319,9 @@ impl BlockChain { } /// Set the cache configuration. - pub fn configure_cache(&mut self, pref_cache_size: usize, max_cache_size: usize) { - self.pref_cache_size = pref_cache_size; - self.max_cache_size = max_cache_size; + pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { + self.pref_cache_size.store(pref_cache_size, AtomicOrder::Relaxed); + self.max_cache_size.store(max_cache_size, AtomicOrder::Relaxed); } /// Returns a tree route between `from` and `to`, which is a tuple of: @@ -435,22 +439,26 @@ impl BlockChain { return; } + let _lock = self.insert_lock.lock(); // store block in db self.blocks_db.put(&hash, &bytes).unwrap(); let (batch, new_best, details) = self.block_to_extras_insert_batch(bytes); - // update best block - let mut best_block = self.best_block.write().unwrap(); - if let Some(b) = new_best { - *best_block = b; + { + // update best block + let mut best_block = self.best_block.write().unwrap(); + if let Some(b) = new_best { + *best_block = b; + } } - // update caches - let mut write = self.block_details.write().unwrap(); - write.remove(&header.parent_hash()); - write.insert(hash.clone(), details); - self.note_used(CacheID::Block(hash)); - + { + // update caches + let mut write = self.block_details.write().unwrap(); + write.remove(&header.parent_hash()); + write.insert(hash.clone(), details); + self.note_used(CacheID::Block(hash)); + } // update extras database self.extras_db.write(batch).unwrap(); } @@ -622,17 +630,17 @@ impl BlockChain { /// Ticks our cache system and throws out any old data. pub fn collect_garbage(&self) { - if self.cache_size().total() < self.pref_cache_size { return; } + if self.cache_size().total() < self.pref_cache_size.load(AtomicOrder::Relaxed) { return; } for _ in 0..COLLECTION_QUEUE_SIZE { { - let mut cache_man = self.cache_man.write().unwrap(); let mut blocks = self.blocks.write().unwrap(); let mut block_details = self.block_details.write().unwrap(); let mut block_hashes = self.block_hashes.write().unwrap(); let mut transaction_addresses = self.transaction_addresses.write().unwrap(); let mut block_logs = self.block_logs.write().unwrap(); let mut blocks_blooms = self.blocks_blooms.write().unwrap(); + let mut cache_man = self.cache_man.write().unwrap(); for id in cache_man.cache_usage.pop_back().unwrap().into_iter() { cache_man.in_use.remove(&id); @@ -650,7 +658,7 @@ impl BlockChain { // TODO: handle block_hashes properly. block_hashes.clear(); } - if self.cache_size().total() < self.max_cache_size { break; } + if self.cache_size().total() < self.max_cache_size.load(AtomicOrder::Relaxed) { break; } } // TODO: m_lastCollection = chrono::system_clock::now(); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 0c8580117..68801520c 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -169,7 +169,7 @@ impl ClientReport { /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. /// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. pub struct Client { - chain: Arc>, + chain: Arc, engine: Arc>, state_db: Mutex, block_queue: BlockQueue, @@ -190,7 +190,7 @@ impl Client { dir.push(format!("v{}-sec-pruned", CLIENT_DB_VER_STR)); let path = dir.as_path(); let gb = spec.genesis_block(); - let chain = Arc::new(RwLock::new(BlockChain::new(&gb, path))); + let chain = Arc::new(BlockChain::new(&gb, path)); let mut opts = Options::new(); opts.set_max_open_files(256); opts.create_if_missing(true); @@ -258,13 +258,13 @@ impl Client { } let header = &block.header; - if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) { + if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.deref()) { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); self.block_queue.mark_as_bad(&header.hash()); bad.insert(block.header.hash()); break; }; - let parent = match self.chain.read().unwrap().block_header(&header.parent_hash) { + let parent = match self.chain.block_header(&header.parent_hash) { Some(p) => p, None => { warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); @@ -278,7 +278,7 @@ impl Client { last_hashes.resize(256, H256::new()); last_hashes[0] = header.parent_hash.clone(); for i in 0..255 { - match self.chain.read().unwrap().block_details(&last_hashes[i]) { + match self.chain.block_details(&last_hashes[i]) { Some(details) => { last_hashes[i + 1] = details.parent.clone(); }, @@ -304,9 +304,9 @@ impl Client { good_blocks.push(header.hash().clone()); - self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? + self.chain.insert_block(&block.bytes); //TODO: err here? let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; - match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { + match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.block_hash(n).unwrap()))) { Ok(_) => (), Err(e) => { warn!(target: "client", "State DB commit failed: {:?}", e); @@ -331,7 +331,7 @@ impl Client { /// Get info on the cache. pub fn cache_info(&self) -> CacheSize { - self.chain.read().unwrap().cache_size() + self.chain.cache_size() } /// Get the report. @@ -341,12 +341,12 @@ impl Client { /// Tick the client. pub fn tick(&self) { - self.chain.read().unwrap().collect_garbage(); + self.chain.collect_garbage(); } /// Set up the cache behaviour. pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { - self.chain.write().unwrap().configure_cache(pref_cache_size, max_cache_size); + self.chain.configure_cache(pref_cache_size, max_cache_size); } fn block_hash(chain: &BlockChain, id: BlockId) -> Option { @@ -361,14 +361,12 @@ impl Client { impl BlockChainClient for Client { fn block_header(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) + Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) } fn block_body(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| { - chain.block(&hash).map(|bytes| { + Self::block_hash(&self.chain, id).and_then(|hash| { + self.chain.block(&hash).map(|bytes| { let rlp = Rlp::new(&bytes); let mut body = RlpStream::new_list(2); body.append_raw(rlp.at(1).as_raw(), 1); @@ -379,24 +377,21 @@ impl BlockChainClient for Client { } fn block(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| { - chain.block(&hash) + Self::block_hash(&self.chain, id).and_then(|hash| { + self.chain.block(&hash) }) } fn block_status(&self, id: BlockId) -> BlockStatus { - let chain = self.chain.read().unwrap(); - match Self::block_hash(&chain, id) { - Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain, + match Self::block_hash(&self.chain, id) { + Some(ref hash) if self.chain.is_known(hash) => BlockStatus::InChain, Some(hash) => self.block_queue.block_status(&hash), None => BlockStatus::Unknown } } fn block_total_difficulty(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) + Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block_details(&hash)).map(|d| d.total_difficulty) } fn code(&self, address: &Address) -> Option { @@ -404,18 +399,17 @@ impl BlockChainClient for Client { } fn transaction(&self, id: TransactionId) -> Option { - let chain = self.chain.read().unwrap(); match id { - TransactionId::Hash(ref hash) => chain.transaction_address(hash), - TransactionId::Location(id, index) => Self::block_hash(&chain, id).map(|hash| TransactionAddress { + TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), + TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress { block_hash: hash, index: index }) - }.and_then(|address| chain.transaction(&address)) + }.and_then(|address| self.chain.transaction(&address)) } fn tree_route(&self, from: &H256, to: &H256) -> Option { - self.chain.read().unwrap().tree_route(from.clone(), to.clone()) + self.chain.tree_route(from.clone(), to.clone()) } fn state_data(&self, _hash: &H256) -> Option { @@ -428,7 +422,7 @@ impl BlockChainClient for Client { fn import_block(&self, bytes: Bytes) -> ImportResult { let header = BlockView::new(&bytes).header(); - if self.chain.read().unwrap().is_known(&header.hash()) { + if self.chain.is_known(&header.hash()) { return Err(ImportError::AlreadyInChain); } if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { @@ -446,13 +440,12 @@ impl BlockChainClient for Client { } fn chain_info(&self) -> BlockChainInfo { - let chain = self.chain.read().unwrap(); BlockChainInfo { - total_difficulty: chain.best_block_total_difficulty(), - pending_total_difficulty: chain.best_block_total_difficulty(), - genesis_hash: chain.genesis_hash(), - best_block_hash: chain.best_block_hash(), - best_block_number: From::from(chain.best_block_number()) + total_difficulty: self.chain.best_block_total_difficulty(), + pending_total_difficulty: self.chain.best_block_total_difficulty(), + genesis_hash: self.chain.genesis_hash(), + best_block_hash: self.chain.best_block_hash(), + best_block_number: From::from(self.chain.best_block_number()) } } } diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index fa9467e95..c7d5e265f 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -57,12 +57,18 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Still operates on a individual block /// Returns a PreVerifiedBlock structure populated with transactions pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { + try!(engine.verify_block_unordered(&header, Some(&bytes))); + for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { + try!(engine.verify_block_unordered(&u, None)); + } // Verify transactions. let mut transactions = Vec::new(); - let v = BlockView::new(&bytes); - for t in v.transactions() { - try!(engine.verify_transaction(&t, &header)); - transactions.push(t); + { + let v = BlockView::new(&bytes); + for t in v.transactions() { + try!(engine.verify_transaction(&t, &header)); + transactions.push(t); + } } Ok(PreVerifiedBlock { header: header, diff --git a/util/src/lib.rs b/util/src/lib.rs index 5c8bd4fb0..2b7438cf3 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -143,7 +143,6 @@ pub mod network; pub mod log; pub mod panics; pub mod keys; -mod thread; pub use common::*; pub use misc::*; @@ -164,5 +163,4 @@ pub use semantic_version::*; pub use network::*; pub use io::*; pub use log::*; -pub use thread::*; diff --git a/util/src/thread.rs b/util/src/thread.rs deleted file mode 100644 index b86ca3e86..000000000 --- a/util/src/thread.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Thread management helpers - -use libc::{c_int, pthread_self, pthread_t}; - -#[repr(C)] -struct sched_param { - priority: c_int, - padding: c_int, -} - -extern { - fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int; - fn pthread_setschedparam(thread: pthread_t, policy: c_int, param: *const sched_param) -> c_int; -} -const PRIO_DARWIN_THREAD: c_int = 3; -const PRIO_DARWIN_BG: c_int = 0x1000; -const SCHED_RR: c_int = 2; - -/// Lower thread priority and put it into background mode -#[cfg(target_os="macos")] -pub fn lower_thread_priority() { - let sp = sched_param { priority: 0, padding: 0 }; - if unsafe { pthread_setschedparam(pthread_self(), SCHED_RR, &sp) } == -1 { - trace!("Could not decrease thread piority"); - } - //unsafe { setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); } -} From 60a8b92e107ecad563dfea5d004abd6d2af7f681 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Tue, 23 Feb 2016 10:14:56 +0100 Subject: [PATCH 176/753] Bumping versions. Fixes #496 --- Cargo.lock | 65 +++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf747f3cc..f87496221 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "parity" version = "0.9.99" dependencies = [ "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", - "ctrlc 1.0.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", + "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -72,7 +72,7 @@ name = "clippy" version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex-syntax 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -107,11 +107,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ctrlc" -version = "1.0.1" -source = "git+https://github.com/tomusdrw/rust-ctrlc.git#d8751b66b31d9698cbb11f8ef37155a8211a0683" +version = "1.1.1" +source = "git+https://github.com/tomusdrw/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -129,7 +128,7 @@ name = "docopt" version = "0.6.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.53 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -145,7 +144,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -158,7 +157,7 @@ dependencies = [ "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -180,10 +179,10 @@ dependencies = [ "ethash 0.9.99", "ethcore-devtools 0.9.99", "ethcore-util 0.9.99", - "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -208,7 +207,7 @@ dependencies = [ "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -225,9 +224,9 @@ dependencies = [ "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", "ethcore-devtools 0.9.99", - "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -238,7 +237,7 @@ dependencies = [ "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -279,8 +278,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "heapsize" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.53 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "hpack" @@ -305,13 +308,13 @@ dependencies = [ "language-tags 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -325,13 +328,13 @@ dependencies = [ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -342,14 +345,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.53 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itertools" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -365,7 +368,7 @@ name = "jsonrpc-core" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -441,7 +444,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -516,12 +519,10 @@ dependencies = [ [[package]] name = "num_cpus" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -557,18 +558,18 @@ dependencies = [ [[package]] name = "regex" -version = "0.1.51" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -619,7 +620,7 @@ dependencies = [ [[package]] name = "serde" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -643,7 +644,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -734,7 +735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicase" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", From c2952b49b429f0c0b4a1cda9cce588fa411ff078 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Tue, 23 Feb 2016 10:47:57 +0100 Subject: [PATCH 177/753] Bumping clippy version Fixes #496 --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 4 ++-- util/Cargo.toml | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f87496221..779220fb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "parity" version = "0.9.99" dependencies = [ - "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -69,7 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.42" +version = "0.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "regex-syntax 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -173,7 +173,7 @@ dependencies = [ name = "ethcore" version = "0.9.99" dependencies = [ - "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", @@ -200,7 +200,7 @@ dependencies = [ name = "ethcore-rpc" version = "0.9.99" dependencies = [ - "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", @@ -218,7 +218,7 @@ name = "ethcore-util" version = "0.9.99" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -250,7 +250,7 @@ dependencies = [ name = "ethsync" version = "0.9.99" dependencies = [ - "clippy 0.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", diff --git a/Cargo.toml b/Cargo.toml index 7fdfc2bee..fbf4b4ca6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ env_logger = "0.3" rustc-serialize = "0.3" docopt = "0.6" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } -clippy = { version = "0.0.42", optional = true } +clippy = { version = "0.0.44", optional = true } ethcore-util = { path = "util" } ethcore = { path = "ethcore" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index d34a5478b..660fdb1b2 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -18,7 +18,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.42", optional = true } +clippy = { version = "0.0.44", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index be06316a4..e36048690 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -16,7 +16,7 @@ jsonrpc-http-server = "1.1" ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } -clippy = { version = "0.0.42", optional = true } +clippy = { version = "0.0.44", optional = true } rustc-serialize = "0.3" serde_macros = { version = "0.6.13", optional = true } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index a99717150..7a81c7d97 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore Date: Tue, 23 Feb 2016 11:40:23 +0100 Subject: [PATCH 178/753] Fixing clippy warnings. Implementing PartialEq for Uints --- ethcore/src/block.rs | 10 +++++----- ethcore/src/ethereum/ethash.rs | 21 +++++++++------------ ethcore/src/evm/interpreter.rs | 7 ++++--- ethcore/src/lib.rs | 2 +- ethcore/src/transaction.rs | 12 +++++++----- hook.sh | 2 +- parity/main.rs | 10 ++++++---- util/src/keys/directory.rs | 2 +- util/src/nibbleslice.rs | 6 +++--- util/src/uint.rs | 29 ++++++++++++++++++++--------- 10 files changed, 57 insertions(+), 44 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index b7590143e..a1194c665 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -48,7 +48,7 @@ impl Block { if urlp.at(1).unwrap().iter().find(|i| i.as_val::().is_err()).is_some() { return false; } - + if !urlp.at(2).unwrap().is_list() { return false; } if urlp.at(2).unwrap().iter().find(|i| i.as_val::
().is_err()).is_some() { return false; @@ -61,7 +61,7 @@ impl Block { impl Decodable for Block { fn decode(decoder: &D) -> Result where D: Decoder { if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() { - return Err(DecoderError::RlpIsTooBig); + return Err(DecoderError::RlpIsTooBig); } let d = decoder.as_rlp(); if d.item_count() != 3 { @@ -87,7 +87,7 @@ pub struct ExecutedBlock { state: State, } -/// A set of references to `ExecutedBlock` fields that are publicly accessible. +/// A set of references to `ExecutedBlock` fields that are publicly accessible. pub struct BlockRefMut<'a> { /// Block header. pub header: &'a Header, @@ -171,7 +171,7 @@ pub struct SealedBlock { impl<'x, 'y> OpenBlock<'x, 'y> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new<'a, 'b>(engine: &'a Engine, db: JournalDB, parent: &Header, last_hashes: &'b LastHashes, author: Address, extra_data: Bytes) -> OpenBlock<'a, 'b> { + pub fn new(engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes, author: Address, extra_data: Bytes) -> Self { let mut r = OpenBlock { block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), engine: engine, @@ -284,7 +284,7 @@ impl<'x, 'y> IsBlock for ClosedBlock<'x, 'y> { } impl<'x, 'y> ClosedBlock<'x, 'y> { - fn new<'a, 'b>(open_block: OpenBlock<'a, 'b>, uncle_bytes: Bytes) -> ClosedBlock<'a, 'b> { + fn new(open_block: OpenBlock<'x, 'y>, uncle_bytes: Bytes) -> Self { ClosedBlock { open_block: open_block, uncle_bytes: uncle_bytes, diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index ff6c6ba72..8c411e7f0 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -87,13 +87,10 @@ impl Engine for Ethash { fn schedule(&self, env_info: &EnvInfo) -> Schedule { trace!(target: "client", "Creating schedule. param={:?}, fCML={}", self.spec().engine_params.get("frontierCompatibilityModeLimit"), self.u64_param("frontierCompatibilityModeLimit")); - match env_info.number < self.u64_param("frontierCompatibilityModeLimit") { - true => { - Schedule::new_frontier() - }, - _ => { - Schedule::new_homestead() - }, + if env_info.number < self.u64_param("frontierCompatibilityModeLimit") { + Schedule::new_frontier() + } else { + Schedule::new_homestead() } } @@ -147,7 +144,7 @@ impl Engine for Ethash { } let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty( - &Ethash::to_ethash(header.bare_hash()), + &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64(), &Ethash::to_ethash(header.mix_hash())))); if difficulty < header.difficulty { @@ -189,7 +186,7 @@ impl Engine for Ethash { let min_gas = parent.gas_limit - parent.gas_limit / gas_limit_divisor; let max_gas = parent.gas_limit + parent.gas_limit / gas_limit_divisor; if header.gas_limit <= min_gas || header.gas_limit >= max_gas { - return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit }))); + return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit }))); } Ok(()) } @@ -220,8 +217,8 @@ impl Ethash { let frontier_limit = self.u64_param("frontierCompatibilityModeLimit"); let mut target = if header.number < frontier_limit { if header.timestamp >= parent.timestamp + duration_limit { - parent.difficulty - (parent.difficulty / difficulty_bound_divisor) - } + parent.difficulty - (parent.difficulty / difficulty_bound_divisor) + } else { parent.difficulty + (parent.difficulty / difficulty_bound_divisor) } @@ -243,7 +240,7 @@ impl Ethash { } target } - + fn boundary_to_difficulty(boundary: &H256) -> U256 { U256::from((U512::one() << 256) / x!(U256::from(boundary.as_slice()))) } diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index e09c37319..7491321cb 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -581,9 +581,10 @@ impl Interpreter { let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); - let value = match instruction == instructions::DELEGATECALL { - true => None, - false => Some(stack.pop_back()) + let value = if instruction == instructions::DELEGATECALL { + None + } else { + Some(stack.pop_back()) }; let in_off = stack.pop_back(); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 9deb3a691..3d43fd725 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -22,7 +22,7 @@ // TODO [todr] not really sure #![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![cfg_attr(feautre="dev", allow(match_bool))] +#![cfg_attr(feature="dev", allow(match_bool))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![cfg_attr(feature="dev", allow(clone_on_copy))] diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index b43c271d3..fc9886a4d 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -37,10 +37,11 @@ impl Default for Action { impl Decodable for Action { fn decode(decoder: &D) -> Result where D: Decoder { let rlp = decoder.as_rlp(); - match rlp.is_empty() { - true => Ok(Action::Create), - false => Ok(Action::Call(try!(rlp.as_val()))) - } + if rlp.is_empty() { + Ok(Action::Create) + } else { + Ok(Action::Call(try!(rlp.as_val()))) + } } } @@ -79,6 +80,7 @@ impl Transaction { } impl FromJson for SignedTransaction { + #[cfg_attr(feature="dev", allow(single_char_pattern))] fn from_json(json: &Json) -> SignedTransaction { let t = Transaction { nonce: xjson!(&json["nonce"]), @@ -110,7 +112,7 @@ impl FromJson for SignedTransaction { impl Transaction { /// The message hash of the transaction. - pub fn hash(&self) -> H256 { + pub fn hash(&self) -> H256 { let mut stream = RlpStream::new(); self.rlp_append_unsigned_transaction(&mut stream); stream.out().sha3() diff --git a/hook.sh b/hook.sh index bb17f4e4f..106ffe4f0 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,3 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test -p ethcore" >> ./.git/hooks/pre-push +echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --features dev" > ./.git/hooks/pre-push chmod +x ./.git/hooks/pre-push diff --git a/parity/main.rs b/parity/main.rs index 328bfc0e2..e25933f2d 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -181,7 +181,7 @@ impl Configuration { } fn _keys_path(&self) -> String { - self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } fn spec(&self) -> Spec { @@ -194,9 +194,10 @@ impl Configuration { } fn normalize_enode(e: &str) -> Option { - match is_valid_node_url(e) { - true => Some(e.to_owned()), - false => None, + if is_valid_node_url(e) { + Some(e.to_owned()) + } else { + None } } @@ -209,6 +210,7 @@ impl Configuration { } } + #[cfg_attr(feature="dev", allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { let mut listen_address = None; let mut public_address = None; diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index bc875db3f..d7db8ac11 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -305,7 +305,7 @@ fn uuid_to_string(uuid: &Uuid) -> String { } fn uuid_from_string(s: &str) -> Result { - let parts: Vec<&str> = s.split("-").collect(); + let parts: Vec<&str> = s.split('-').collect(); if parts.len() != 5 { return Err(UtilError::BadSize); } let mut uuid = H128::zero(); diff --git a/util/src/nibbleslice.rs b/util/src/nibbleslice.rs index 047990368..e10def40a 100644 --- a/util/src/nibbleslice.rs +++ b/util/src/nibbleslice.rs @@ -69,13 +69,13 @@ impl<'a> Iterator for NibbleSliceIterator<'a> { impl<'a, 'view> NibbleSlice<'a> where 'a: 'view { /// Create a new nibble slice with the given byte-slice. - pub fn new(data: &[u8]) -> NibbleSlice { NibbleSlice::new_offset(data, 0) } + pub fn new(data: &'a [u8]) -> Self { NibbleSlice::new_offset(data, 0) } /// Create a new nibble slice with the given byte-slice with a nibble offset. - pub fn new_offset(data: &'a [u8], offset: usize) -> NibbleSlice { NibbleSlice{data: data, offset: offset, data_encode_suffix: &b""[..], offset_encode_suffix: 0} } + pub fn new_offset(data: &'a [u8], offset: usize) -> Self { NibbleSlice{data: data, offset: offset, data_encode_suffix: &b""[..], offset_encode_suffix: 0} } /// Create a composed nibble slice; one followed by the other. - pub fn new_composed(a: &'a NibbleSlice, b: &'a NibbleSlice) -> NibbleSlice<'a> { NibbleSlice{data: a.data, offset: a.offset, data_encode_suffix: b.data, offset_encode_suffix: b.offset} } + pub fn new_composed(a: &'a NibbleSlice, b: &'a NibbleSlice) -> Self { NibbleSlice{data: a.data, offset: a.offset, data_encode_suffix: b.data, offset_encode_suffix: b.offset} } /*pub fn new_composed_bytes_offset(a: &NibbleSlice, b: &NibbleSlice) -> (Bytes, usize) { let r: Vec::with_capacity((a.len() + b.len() + 1) / 2); diff --git a/util/src/uint.rs b/util/src/uint.rs index 7206a521e..906bd91d0 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -31,7 +31,7 @@ // //! Big unsigned integer types -//! +//! //! Implementation of a various large-but-fixed sized unsigned integer types. //! The functions here are designed to be fast. //! @@ -99,7 +99,7 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + /// Conversion to u64 with overflow checking fn as_u64(&self) -> u64; - + /// Return the least number of bits needed to represent the number fn bits(&self) -> usize; /// Return if specific bit is set @@ -124,7 +124,7 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + /// Multiple this `Uint` with other returning result and possible overflow fn overflowing_mul(self, other: Self) -> (Self, bool); - + /// Divide this `Uint` by other returning result and possible overflow fn overflowing_div(self, other: Self) -> (Self, bool); @@ -133,7 +133,7 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + /// Returns negation of this `Uint` and overflow (always true) fn overflowing_neg(self) -> (Self, bool); - + /// Shifts this `Uint` and returns overflow fn overflowing_shl(self, shift: u32) -> (Self, bool); } @@ -141,7 +141,7 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + macro_rules! construct_uint { ($name:ident, $n_words:expr) => ( /// Little-endian large integer type - #[derive(Copy, Clone, Eq, PartialEq)] + #[derive(Copy, Clone, Eq)] pub struct $name(pub [u64; $n_words]); impl Uint for $name { @@ -175,7 +175,7 @@ macro_rules! construct_uint { fn as_u32(&self) -> u32 { let &$name(ref arr) = self; if (arr[0] & (0xffffffffu64 << 32)) != 0 { - panic!("Integer overflow when casting U256") + panic!("Integer overflow when casting U256") } self.as_u64() as u32 } @@ -186,7 +186,7 @@ macro_rules! construct_uint { let &$name(ref arr) = self; for i in 1..$n_words { if arr[i] != 0 { - panic!("Integer overflow when casting U256") + panic!("Integer overflow when casting U256") } } arr[0] @@ -320,7 +320,7 @@ macro_rules! construct_uint { if b_carry { let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow); (ret, overflow) - } else { + } else { ($name(ret), overflow) } } @@ -448,7 +448,7 @@ macro_rules! construct_uint { } impl serde::Serialize for $name { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { let mut hex = "0x".to_owned(); let mut bytes = [0u8; 8 * $n_words]; @@ -791,6 +791,17 @@ macro_rules! construct_uint { } } + impl PartialEq for $name { + fn eq(&self, other: &$name) -> bool { + let &$name(ref me) = self; + let &$name(ref you) = other; + for i in 0..$n_words { + if me[$n_words - 1 - i] != you[$n_words - 1 - i] { return false; } + } + true + } + } + impl Hash for $name { fn hash(&self, state: &mut H) where H: Hasher { unsafe { state.write(::std::slice::from_raw_parts(self.0.as_ptr() as *mut u8, self.0.len() * 8)); } From 3734959f55fbc9967286511aa48af1aa6dece2fa Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Tue, 23 Feb 2016 11:54:10 +0100 Subject: [PATCH 179/753] Deriving PartialEq and disabling clippy warning --- util/src/uint.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 906bd91d0..6490cbd9b 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -141,7 +141,7 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + macro_rules! construct_uint { ($name:ident, $n_words:expr) => ( /// Little-endian large integer type - #[derive(Copy, Clone, Eq)] + #[derive(Copy, Clone, Eq, PartialEq)] pub struct $name(pub [u64; $n_words]); impl Uint for $name { @@ -791,17 +791,7 @@ macro_rules! construct_uint { } } - impl PartialEq for $name { - fn eq(&self, other: &$name) -> bool { - let &$name(ref me) = self; - let &$name(ref you) = other; - for i in 0..$n_words { - if me[$n_words - 1 - i] != you[$n_words - 1 - i] { return false; } - } - true - } - } - + #[cfg_attr(feature="dev", allow(derive_hash_xor_eq))] // We are pretty sure it's ok. impl Hash for $name { fn hash(&self, state: &mut H) where H: Hasher { unsafe { state.write(::std::slice::from_raw_parts(self.0.as_ptr() as *mut u8, self.0.len() * 8)); } From 492bf7154e66027344597a8842af9eeb3590e04d Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 23 Feb 2016 15:02:08 +0100 Subject: [PATCH 180/753] Log address --- util/src/network/host.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index fb3150ad3..8dd9eb9cc 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -500,7 +500,7 @@ impl Host where Message: Send + Sync + Clone { match TcpStream::connect(&address) { Ok(socket) => socket, Err(e) => { - warn!("Can't connect to node: {:?}", e); + warn!("Can't connect to address {:?}: {:?}", address, e); return; } } From 990c5c8faa6cded59257846bd58039e0c48ad085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 23 Feb 2016 18:44:13 +0100 Subject: [PATCH 181/753] Refactoring client and fixing mark_as_bad & SyncMessage bugs --- ethcore/src/client.rs | 145 +++++++++++++++++++++++++---------------- ethcore/src/service.rs | 7 +- 2 files changed, 95 insertions(+), 57 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c3ec4b4d0..aa71fbbfa 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -22,7 +22,7 @@ use rocksdb::{Options, DB, DBCompactionStyle}; use blockchain::{BlockChain, BlockProvider, CacheSize}; use views::BlockView; use error::*; -use header::BlockNumber; +use header::{BlockNumber, Header}; use state::State; use spec::Spec; use engine::Engine; @@ -243,85 +243,117 @@ impl Client { self.block_queue.write().unwrap().flush(); } + fn build_last_hashes(&self, header: &Header) -> LastHashes { + let mut last_hashes = LastHashes::new(); + last_hashes.resize(256, H256::new()); + last_hashes[0] = header.parent_hash.clone(); + let chain = self.chain.read().unwrap(); + for i in 0..255 { + match chain.block_details(&last_hashes[i]) { + Some(details) => { + last_hashes[i + 1] = details.parent.clone(); + }, + None => break, + } + } + last_hashes + } + /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self, io: &IoChannel) -> usize { - let mut ret = 0; - let mut bad = HashSet::new(); + let max_blocks_to_import = 128; + + let mut imported = 0; + let mut good_blocks = Vec::with_capacity(max_blocks_to_import); + let mut bad_blocks = HashSet::new(); + let engine = self.engine.deref().deref(); + let _import_lock = self.import_lock.lock(); - let blocks = self.block_queue.write().unwrap().drain(128); - let mut good_blocks = Vec::with_capacity(128); + let blocks = self.block_queue.write().unwrap().drain(max_blocks_to_import); + for block in blocks { - if bad.contains(&block.header.parent_hash) { - self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); - bad.insert(block.header.hash()); + let header = &block.header; + let header_hash = block.header.hash(); + let bad_contains_parent = bad_blocks.contains(&header.parent_hash); + + let mark_block_as_bad = || { + self.block_queue.write().unwrap().mark_as_bad(&header_hash); + bad_blocks.insert(header_hash); + }; + + if bad_contains_parent { + mark_block_as_bad(); continue; } - let header = &block.header; - if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) { + // Verify Block Family + let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); + if let Err(e) = verify_family_result { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); - bad.insert(block.header.hash()); + mark_block_as_bad(); break; }; - let parent = match self.chain.read().unwrap().block_header(&header.parent_hash) { - Some(p) => p, - None => { - warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); - bad.insert(block.header.hash()); - break; - }, - }; - // build last hashes - let mut last_hashes = LastHashes::new(); - last_hashes.resize(256, H256::new()); - last_hashes[0] = header.parent_hash.clone(); - for i in 0..255 { - match self.chain.read().unwrap().block_details(&last_hashes[i]) { - Some(details) => { - last_hashes[i + 1] = details.parent.clone(); - }, - None => break, - } - } + // Check if Parent is in chain + let chain_has_parent = self.chain.read().unwrap().block_header(&header.parent_hash); + if let None = chain_has_parent { + warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); + mark_block_as_bad(); + break; + }; + + // Enact Verified Block + let parent = chain_has_parent.unwrap(); + let last_hashes = self.build_last_hashes(header); let db = self.state_db.lock().unwrap().clone(); - let result = match enact_verified(&block, self.engine.deref().deref(), db, &parent, &last_hashes) { - Ok(b) => b, - Err(e) => { - warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - bad.insert(block.header.hash()); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); - break; - } + + let enact_result = enact_verified(&block, engine, db, &parent, &last_hashes); + if let Err(e) = enact_result { + warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); + mark_block_as_bad(); + break; }; - if let Err(e) = verify_block_final(&header, result.block().header()) { + + // Final Verification + let enact_result = enact_result.unwrap(); + if let Err(e) = verify_block_final(&header, enact_result.block().header()) { warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + mark_block_as_bad(); break; } - good_blocks.push(header.hash().clone()); - + // Insert block self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? - let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; - match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { - Ok(_) => (), - Err(e) => { - warn!(target: "client", "State DB commit failed: {:?}", e); - break; - } + good_blocks.push(header.hash()); + + let ancient = if header.number() >= HISTORY { + let n = header.number() - HISTORY; + let chain = self.chain.read().unwrap(); + Some((n, chain.block_hash(n).unwrap())) + } else { + None + }; + + // Commit results + let commit_result = enact_result.drain().commit(header.number(), &header.hash(), ancient); + if let Err(e) = commit_result { + warn!(target: "client", "State DB commit failed: {:?}", e); + break; } + self.report.write().unwrap().accrue_block(&block); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); - ret += 1; + imported += 1; } + self.block_queue.write().unwrap().mark_as_good(&good_blocks); if !good_blocks.is_empty() && self.block_queue.read().unwrap().queue_info().is_empty() { - io.send(NetworkIoMessage::User(SyncMessage::BlockVerified)).unwrap(); + io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { + good: good_blocks, + bad: bad_blocks.into_iter().collect(), + })).unwrap(); } - ret + imported } /// Get a copy of the best block's state. @@ -393,7 +425,7 @@ impl BlockChainClient for Client { None => BlockStatus::Unknown } } - + fn block_total_difficulty(&self, id: BlockId) -> Option { let chain = self.chain.read().unwrap(); Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) @@ -435,6 +467,7 @@ impl BlockChainClient for Client { return Err(ImportError::UnknownParent); } self.block_queue.write().unwrap().import_block(bytes) + // TODO [ToDr] remove transactions } fn queue_info(&self) -> BlockQueueInfo { diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 534aab49d..cdf3425e8 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -26,7 +26,12 @@ use client::Client; #[derive(Clone)] pub enum SyncMessage { /// New block has been imported into the blockchain - NewChainBlock(Bytes), //TODO: use Cow + NewChainBlocks { + /// Hashes of blocks imported to blockchain + good: Vec, + /// Hashes of blocks not imported to blockchain + bad: Vec, + }, /// A block is ready BlockVerified, } From 4084acd869f53e0695bed887bcf33578b611c681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 23 Feb 2016 18:51:18 +0100 Subject: [PATCH 182/753] Removing dangling comment --- ethcore/src/client.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index aa71fbbfa..87dba3dd5 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -467,7 +467,6 @@ impl BlockChainClient for Client { return Err(ImportError::UnknownParent); } self.block_queue.write().unwrap().import_block(bytes) - // TODO [ToDr] remove transactions } fn queue_info(&self) -> BlockQueueInfo { From 35cabecad885997ffa328b6b123de5a8ae12dfb8 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 23 Feb 2016 18:51:29 +0100 Subject: [PATCH 183/753] support for polling --- Cargo.lock | 9 ++ ethcore/src/filter.rs | 16 ++++ rpc/Cargo.toml | 1 + rpc/src/lib.rs | 1 + rpc/src/v1/helpers/mod.rs | 21 +++++ rpc/src/v1/helpers/poll_filter.rs | 10 ++ rpc/src/v1/helpers/poll_indexer.rs | 144 +++++++++++++++++++++++++++++ rpc/src/v1/impls/eth.rs | 73 +++++++++++++-- rpc/src/v1/mod.rs | 1 + 9 files changed, 267 insertions(+), 9 deletions(-) create mode 100644 rpc/src/v1/helpers/mod.rs create mode 100644 rpc/src/v1/helpers/poll_filter.rs create mode 100644 rpc/src/v1/helpers/poll_indexer.rs diff --git a/Cargo.lock b/Cargo.lock index 779220fb6..fe1122195 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,6 +211,7 @@ dependencies = [ "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "transient-hashmap 0.1.0 (git+https://github.com/debris/transient-hashmap)", ] [[package]] @@ -728,6 +729,14 @@ name = "traitobject" version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "transient-hashmap" +version = "0.1.0" +source = "git+https://github.com/debris/transient-hashmap#e21bf844277785504ddc30ee22d2a709103d4992" +dependencies = [ + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "typeable" version = "0.1.2" diff --git a/ethcore/src/filter.rs b/ethcore/src/filter.rs index f5f9135d6..73aea8ccc 100644 --- a/ethcore/src/filter.rs +++ b/ethcore/src/filter.rs @@ -42,6 +42,22 @@ pub struct Filter { pub topics: [Option>; 4], } +impl Clone for Filter { + fn clone(&self) -> Self { + let mut topics = [None, None, None, None]; + for i in 0..4 { + topics[i] = self.topics[i].clone(); + } + + Filter { + from_block: self.from_block.clone(), + to_block: self.to_block.clone(), + address: self.address.clone(), + topics: topics + } + } +} + impl Filter { /// Returns combinations of each address and topic. pub fn bloom_possibilities(&self) -> Vec { diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index e36048690..03cffbb85 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -19,6 +19,7 @@ ethsync = { path = "../sync" } clippy = { version = "0.0.44", optional = true } rustc-serialize = "0.3" serde_macros = { version = "0.6.13", optional = true } +transient-hashmap = { git = "https://github.com/debris/transient-hashmap" } [build-dependencies] serde_codegen = { version = "0.6.13", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index d7b5bdc3b..70d6fae82 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -27,6 +27,7 @@ extern crate jsonrpc_http_server; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; +extern crate transient_hashmap; #[cfg(feature = "serde_macros")] include!("lib.rs.in"); diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs new file mode 100644 index 000000000..d212d74ab --- /dev/null +++ b/rpc/src/v1/helpers/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +mod poll_indexer; +mod poll_filter; + +pub use self::poll_indexer::PollIndexer; +pub use self::poll_filter::PollFilter; diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs new file mode 100644 index 000000000..465290270 --- /dev/null +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -0,0 +1,10 @@ +//! Helper type with all filter possibilities. + +use ethcore::filter::Filter; + +#[derive(Clone)] +pub enum PollFilter { + Block, + PendingTransaction, + Logs(Filter) +} diff --git a/rpc/src/v1/helpers/poll_indexer.rs b/rpc/src/v1/helpers/poll_indexer.rs new file mode 100644 index 000000000..11cb30935 --- /dev/null +++ b/rpc/src/v1/helpers/poll_indexer.rs @@ -0,0 +1,144 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Indexes all rpc poll requests. + +use transient_hashmap::{TransientHashMap, Timer, StandardTimer}; + +/// Lifetime of poll (in seconds). +const POLL_LIFETIME: u64 = 60; + +pub type PollId = usize; +pub type BlockNumber = u64; + +pub struct PollInfo { + pub filter: F, + pub block_number: BlockNumber +} + +impl Clone for PollInfo where F: Clone { + fn clone(&self) -> Self { + PollInfo { + filter: self.filter.clone(), + block_number: self.block_number.clone() + } + } +} + +/// Indexes all poll requests. +/// +/// Lazily garbage collects unused polls info. +pub struct PollIndexer where T: Timer { + polls: TransientHashMap, T>, + next_available_id: PollId +} + +impl PollIndexer { + /// Creates new instance of indexer. + pub fn new() -> Self { + PollIndexer::new_with_timer(Default::default()) + } +} + +impl PollIndexer where T: Timer { + pub fn new_with_timer(timer: T) -> Self { + PollIndexer { + polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), + next_available_id: 0 + } + } + + /// Returns id which can be used for new poll. + /// + /// Stores information when last poll happend. + pub fn create_poll(&mut self, filter: F, block: BlockNumber) -> PollId { + self.polls.prune(); + let id = self.next_available_id; + self.next_available_id += 1; + self.polls.insert(id, PollInfo { + filter: filter, + block_number: block + }); + id + } + + /// Updates information when last poll happend. + pub fn update_poll(&mut self, id: &PollId, block: BlockNumber) { + self.polls.prune(); + if let Some(info) = self.polls.get_mut(id) { + info.block_number = block; + } + } + + /// Returns number of block when last poll happend. + pub fn get_poll(&mut self, id: &PollId) -> Option<&PollInfo> { + self.polls.prune(); + self.polls.get(id) + } + + /// Removes poll info. + pub fn remove_poll(&mut self, id: &PollId) { + self.polls.remove(id); + } +} + +#[cfg(test)] +mod tests { + use std::cell::RefCell; + use transient_hashmap::Timer; + use v1::helpers::PollIndexer; + + struct TestTimer<'a> { + time: &'a RefCell + } + + impl<'a> Timer for TestTimer<'a> { + fn get_time(&self) -> i64 { + *self.time.borrow() + } + } + + #[test] + fn test_poll_indexer() { + let time = RefCell::new(0); + let timer = TestTimer { + time: &time + }; + + let mut indexer = PollIndexer::new_with_timer(timer); + assert_eq!(indexer.create_poll(false, 20), 0); + assert_eq!(indexer.create_poll(true, 20), 1); + + *time.borrow_mut() = 10; + indexer.update_poll(&0, 21); + assert_eq!(indexer.get_poll(&0).unwrap().filter, false); + assert_eq!(indexer.get_poll(&0).unwrap().block_number, 21); + + *time.borrow_mut() = 30; + indexer.update_poll(&1, 23); + assert_eq!(indexer.get_poll(&1).unwrap().filter, true); + assert_eq!(indexer.get_poll(&1).unwrap().block_number, 23); + + *time.borrow_mut() = 75; + indexer.update_poll(&0, 30); + assert!(indexer.get_poll(&0).is_none()); + assert_eq!(indexer.get_poll(&1).unwrap().filter, true); + assert_eq!(indexer.get_poll(&1).unwrap().block_number, 23); + + indexer.remove_poll(&1); + assert!(indexer.get_poll(&1).is_none()); + } +} diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 689afd019..153a51216 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Eth rpc implementation. -use std::sync::Arc; +use std::sync::{Mutex, Arc}; use ethsync::{EthSync, SyncState}; use jsonrpc_core::*; use util::hash::*; @@ -26,6 +26,7 @@ use ethcore::views::*; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; +use v1::helpers::{PollFilter, PollIndexer}; /// Eth rpc implementation. pub struct EthClient { @@ -212,28 +213,82 @@ impl Eth for EthClient { /// Eth filter rpc implementation. pub struct EthFilterClient { - client: Arc + client: Arc, + polls: Mutex> } impl EthFilterClient { /// Creates new Eth filter client. pub fn new(client: Arc) -> Self { EthFilterClient { - client: client + client: client, + polls: Mutex::new(PollIndexer::new()) } } } impl EthFilter for EthFilterClient { - fn new_block_filter(&self, _params: Params) -> Result { - Ok(Value::U64(0)) + fn new_filter(&self, params: Params) -> Result { + from_params::<(Filter,)>(params) + .and_then(|(filter,)| { + let mut polls = self.polls.lock().unwrap(); + let id = polls.create_poll(PollFilter::Logs(filter.into()), self.client.chain_info().best_block_number); + to_value(&U256::from(id)) + }) } - fn new_pending_transaction_filter(&self, _params: Params) -> Result { - Ok(Value::U64(1)) + fn new_block_filter(&self, params: Params) -> Result { + match params { + Params::None => { + let mut polls = self.polls.lock().unwrap(); + let id = polls.create_poll(PollFilter::Block, self.client.chain_info().best_block_number); + to_value(&U256::from(id)) + }, + _ => Err(Error::invalid_params()) + } } - fn filter_changes(&self, _: Params) -> Result { - to_value(&self.client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) + fn new_pending_transaction_filter(&self, params: Params) -> Result { + match params { + Params::None => { + let mut polls = self.polls.lock().unwrap(); + let id = polls.create_poll(PollFilter::PendingTransaction, self.client.chain_info().best_block_number); + to_value(&U256::from(id)) + }, + _ => Err(Error::invalid_params()) + } + } + + fn filter_changes(&self, params: Params) -> Result { + from_params::<(Index,)>(params) + .and_then(|(index,)| { + let info = self.polls.lock().unwrap().get_poll(&index.value()).cloned(); + match info { + None => Ok(Value::Array(vec![] as Vec)), + Some(info) => match info.filter { + PollFilter::Block => { + //unimplemented!() + to_value(&self.client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) + }, + PollFilter::PendingTransaction => { + //unimplemented!() + to_value(&self.client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) + }, + PollFilter::Logs(mut filter) => { + filter.from_block = BlockId::Number(info.block_number); + filter.to_block = BlockId::Latest; + let logs = self.client.logs(filter) + .into_iter() + .map(From::from) + .collect::>(); + + let current_number = self.client.chain_info().best_block_number; + self.polls.lock().unwrap().update_poll(&index.value(), current_number); + + to_value(&logs) + } + } + } + }) } } diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 01635e872..57f7a944a 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -23,6 +23,7 @@ mod impls; mod types; #[cfg(test)] mod tests; +mod helpers; pub use self::traits::{Web3, Eth, EthFilter, Net}; pub use self::impls::*; From 8beba717f8456fa205471a02eb3472a41fa320fd Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 23 Feb 2016 19:38:06 +0100 Subject: [PATCH 184/753] Delayed UPnP initialization --- parity/main.rs | 6 +- util/src/network/host.rs | 136 +++++++++++++++++++++--------------- util/src/network/service.rs | 1 - 3 files changed, 84 insertions(+), 59 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index e25933f2d..79ee41590 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -73,7 +73,7 @@ Options: --address URL Equivalent to --listen-address URL --public-address URL. --peers NUM Try to manintain that many peers [default: 25]. --no-discovery Disable new peer discovery. - --upnp Use UPnP to try to figure out the correct network settings. + --no-upnp Disable trying to figure out the correct public adderss over UPnP. --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. @@ -101,7 +101,7 @@ struct Args { flag_address: Option, flag_peers: u32, flag_no_discovery: bool, - flag_upnp: bool, + flag_no_upnp: bool, flag_node_key: Option, flag_cache_pref_size: usize, flag_cache_max_size: usize, @@ -233,7 +233,7 @@ impl Configuration { fn net_settings(&self, spec: &Spec) -> NetworkConfiguration { let mut ret = NetworkConfiguration::new(); - ret.nat_enabled = self.args.flag_upnp; + ret.nat_enabled = !self.args.flag_no_upnp; ret.boot_nodes = self.init_nodes(spec); let (listen, public) = self.net_addresses(); ret.listen_address = listen; diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 8dd9eb9cc..feb342700 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -106,6 +106,7 @@ const IDLE: usize = LAST_HANDSHAKE + 2; const DISCOVERY: usize = LAST_HANDSHAKE + 3; const DISCOVERY_REFRESH: usize = LAST_HANDSHAKE + 4; const DISCOVERY_ROUND: usize = LAST_HANDSHAKE + 5; +const INIT_PUBLIC: usize = LAST_HANDSHAKE + 6; const FIRST_SESSION: usize = 0; const LAST_SESSION: usize = FIRST_SESSION + MAX_SESSIONS - 1; const FIRST_HANDSHAKE: usize = LAST_SESSION + 1; @@ -261,7 +262,9 @@ pub struct HostInfo { /// TCP connection port. pub listen_port: u16, /// Registered capabilities (handlers) - pub capabilities: Vec + pub capabilities: Vec, + /// Public address + discovery port + public_endpoint: NodeEndpoint, } impl HostInfo { @@ -294,16 +297,15 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, - tcp_listener: Mutex, + tcp_listener: Mutex>, handshakes: Arc>>, sessions: Arc>>, - discovery: Option>, + discovery: Mutex>, nodes: RwLock, handlers: RwLock>>>, timers: RwLock>, timer_counter: RwLock, stats: Arc, - public_endpoint: NodeEndpoint, pinned_nodes: Vec, } @@ -316,27 +318,6 @@ impl Host where Message: Send + Sync + Clone { }; let udp_port = config.udp_port.unwrap_or(listen_address.port()); - let public_endpoint = match config.public_address { - None => { - let public_address = select_public_address(listen_address.port()); - let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; - if config.nat_enabled { - match map_external_address(&local_endpoint) { - Some(endpoint) => { - info!("NAT Mappped to external address {}", endpoint.address); - endpoint - }, - None => local_endpoint - } - } else { - local_endpoint - } - } - Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port } - }; - - // Setup the server socket - let tcp_listener = TcpListener::bind(&listen_address).unwrap(); let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { @@ -350,10 +331,8 @@ impl Host where Message: Send + Sync + Clone { }, |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; - let discovery = if config.discovery_enabled && !config.pin { - Some(Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY)) - } else { None }; let path = config.config_path.clone(); + let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port }; let mut host = Host:: { info: RwLock::new(HostInfo { keys: keys, @@ -363,9 +342,10 @@ impl Host where Message: Send + Sync + Clone { client_version: version(), listen_port: 0, capabilities: Vec::new(), + public_endpoint: local_endpoint, // will be replaced by public once it is resolved }), - discovery: discovery.map(Mutex::new), - tcp_listener: Mutex::new(tcp_listener), + discovery: Mutex::new(None), + tcp_listener: Mutex::new(None), handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), @@ -373,16 +353,12 @@ impl Host where Message: Send + Sync + Clone { timers: RwLock::new(HashMap::new()), timer_counter: RwLock::new(USER_TIMER), stats: Arc::new(NetworkStats::default()), - public_endpoint: public_endpoint, pinned_nodes: Vec::new(), }; let port = listen_address.port(); host.info.write().unwrap().deref_mut().listen_port = port; let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); - if let Some(ref mut discovery) = host.discovery { - discovery.lock().unwrap().init_node_list(host.nodes.read().unwrap().unordered_entries()); - } for n in boot_nodes { host.add_node(&n); } @@ -400,8 +376,8 @@ impl Host where Message: Send + Sync + Clone { let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; self.pinned_nodes.push(n.id.clone()); self.nodes.write().unwrap().add_node(n); - if let Some(ref mut discovery) = self.discovery { - discovery.lock().unwrap().add_node(entry); + if let &mut Some(ref mut discovery) = self.discovery.lock().unwrap().deref_mut() { + discovery.add_node(entry); } } } @@ -412,7 +388,61 @@ impl Host where Message: Send + Sync + Clone { } pub fn client_url(&self) -> String { - format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.public_endpoint.clone())) + format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().public_endpoint.clone())) + } + + fn init_public_interface(&self, io: &IoContext>) { + io.clear_timer(INIT_PUBLIC).unwrap(); + let mut tcp_listener = self.tcp_listener.lock().unwrap(); + if tcp_listener.is_some() { + return; + } + // public_endpoint in host info contains local adderss at this point + let listen_address = self.info.read().unwrap().public_endpoint.address.clone(); + let udp_port = self.info.read().unwrap().config.udp_port.unwrap_or(listen_address.port()); + let public_endpoint = match self.info.read().unwrap().config.public_address { + None => { + let public_address = select_public_address(listen_address.port()); + let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; + if self.info.read().unwrap().config.nat_enabled { + match map_external_address(&local_endpoint) { + Some(endpoint) => { + info!("NAT mappped to external address {}", endpoint.address); + endpoint + }, + None => local_endpoint + } + } else { + local_endpoint + } + } + Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port } + }; + + // Setup the server socket + *tcp_listener = Some(TcpListener::bind(&listen_address).unwrap()); + self.info.write().unwrap().public_endpoint = public_endpoint.clone(); + io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); + info!("Public node URL: {}", self.client_url()); + + // Initialize discovery. + let discovery = { + let info = self.info.read().unwrap(); + if info.config.discovery_enabled && !info.config.pin { + Some(Discovery::new(&info.keys, listen_address.clone(), public_endpoint, DISCOVERY)) + } else { None } + }; + + if let Some(mut discovery) = discovery { + discovery.init_node_list(self.nodes.read().unwrap().unordered_entries()); + for n in self.nodes.read().unwrap().unordered_entries() { + discovery.add_node(n.clone()); + } + io.register_stream(DISCOVERY).expect("Error registering UDP listener"); + io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); + io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); + *self.discovery.lock().unwrap().deref_mut() = Some(discovery); + } } fn maintain_network(&self, io: &IoContext>) { @@ -526,7 +556,7 @@ impl Host where Message: Send + Sync + Clone { fn accept(&self, io: &IoContext>) { trace!(target: "network", "Accepting incoming connection"); loop { - let socket = match self.tcp_listener.lock().unwrap().accept() { + let socket = match self.tcp_listener.lock().unwrap().as_ref().unwrap().accept() { Ok(None) => break, Ok(Some((sock, _addr))) => sock, Err(e) => { @@ -666,8 +696,9 @@ impl Host where Message: Send + Sync + Clone { if let Ok(address) = session.remote_addr() { let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); - if let Some(ref discovery) = self.discovery { - discovery.lock().unwrap().add_node(entry); + let mut discovery = self.discovery.lock().unwrap(); + if let &mut Some(ref mut discovery) = discovery.deref_mut() { + discovery.add_node(entry); } } } @@ -760,13 +791,8 @@ impl Host where Message: Send + Sync + Clone { impl IoHandler> for Host where Message: Send + Sync + Clone + 'static { /// Initialize networking fn initialize(&self, io: &IoContext>) { - io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer"); - if self.discovery.is_some() { - io.register_stream(DISCOVERY).expect("Error registering UDP listener"); - io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); - io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); - } + io.register_timer(INIT_PUBLIC, 0).expect("Error registering initialization timer"); self.maintain_network(io) } @@ -784,7 +810,7 @@ impl IoHandler> for Host where Messa FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), DISCOVERY => { - let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().readable() }; + let node_changes = { self.discovery.lock().unwrap().as_mut().unwrap().readable() }; if let Some(node_changes) = node_changes { self.update_nodes(io, node_changes); } @@ -800,7 +826,7 @@ impl IoHandler> for Host where Messa FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io), DISCOVERY => { - self.discovery.as_ref().unwrap().lock().unwrap().writable(); + self.discovery.lock().unwrap().as_mut().unwrap().writable(); io.update_registration(DISCOVERY).expect("Error updating discovery registration"); } _ => panic!("Received unknown writable token"), @@ -810,14 +836,15 @@ impl IoHandler> for Host where Messa fn timeout(&self, io: &IoContext>, token: TimerToken) { match token { IDLE => self.maintain_network(io), + INIT_PUBLIC => self.init_public_interface(io), FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { - self.discovery.as_ref().unwrap().lock().unwrap().refresh(); + self.discovery.lock().unwrap().as_mut().unwrap().refresh(); io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, DISCOVERY_ROUND => { - let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().round() }; + let node_changes = { self.discovery.lock().unwrap().as_mut().unwrap().round() }; if let Some(node_changes) = node_changes { self.update_nodes(io, node_changes); } @@ -892,8 +919,8 @@ impl IoHandler> for Host where Messa connection.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); } } - DISCOVERY => self.discovery.as_ref().unwrap().lock().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), - TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), + DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), + TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } } @@ -915,7 +942,6 @@ impl IoHandler> for Host where Messa } } DISCOVERY => (), - TCP_ACCEPT => event_loop.deregister(self.tcp_listener.lock().unwrap().deref()).unwrap(), _ => warn!("Unexpected stream deregistration") } } @@ -934,8 +960,8 @@ impl IoHandler> for Host where Messa connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); } } - DISCOVERY => self.discovery.as_ref().unwrap().lock().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), - TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), + DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), + TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } } diff --git a/util/src/network/service.rs b/util/src/network/service.rs index 1cd48abe1..7b9388e85 100644 --- a/util/src/network/service.rs +++ b/util/src/network/service.rs @@ -42,7 +42,6 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat let host = Arc::new(Host::new(config)); let stats = host.stats().clone(); let host_info = host.client_version(); - info!("Node URL: {}", host.client_url()); try!(io_service.register_handler(host)); Ok(NetworkService { io_service: io_service, From 40f908a49985129c612b7f31943c8034c4342053 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 23 Feb 2016 20:14:37 +0100 Subject: [PATCH 185/753] Log formatting --- Cargo.lock | 1 + Cargo.toml | 1 + parity/main.rs | 13 ++++++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 779220fb6..d1ef76816 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fbf4b4ca6..2de097ad9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" docopt = "0.6" +time = "0.1" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } clippy = { version = "0.0.44", optional = true } ethcore-util = { path = "util" } diff --git a/parity/main.rs b/parity/main.rs index e25933f2d..1b6a59a93 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -30,6 +30,7 @@ extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate daemonize; +extern crate time; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -38,7 +39,6 @@ use std::net::{SocketAddr}; use std::env; use std::process::exit; use std::path::PathBuf; -use rlog::{LogLevelFilter}; use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; @@ -112,6 +112,8 @@ struct Args { } fn setup_log(init: &Option) { + use rlog::*; + let mut builder = LogBuilder::new(); builder.filter(None, LogLevelFilter::Info); @@ -123,6 +125,15 @@ fn setup_log(init: &Option) { builder.parse(s); } + let format = |record: &LogRecord| { + let timestamp = time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now()).unwrap(); + if max_log_level() <= LogLevelFilter::Info { + format!("{}{}", timestamp, record.args()) + } else { + format!("{}{}:{}: {}", timestamp, record.level(), record.target(), record.args()) + } + }; + builder.format(format); builder.init().unwrap(); } From 5bd355e0af9baf2b831c8ebc19e166794b42d5c6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 24 Feb 2016 09:55:09 +0300 Subject: [PATCH 186/753] removing extra crate --- ethtools/Cargo.toml | 13 ---------- ethtools/README.md | 1 - ethtools/src/lib.rs | 24 ----------------- ...--3f49624084b67849c7b4e805c5988c21a430f9d9 | 0 ...--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf | 0 util/src/keys/directory.rs | 2 ++ .../src/keys/geth_import.rs | 26 +++++++------------ util/src/keys/mod.rs | 1 + util/src/keys/store.rs | 14 ++++++++++ 9 files changed, 26 insertions(+), 55 deletions(-) delete mode 100644 ethtools/Cargo.toml delete mode 100644 ethtools/README.md delete mode 100644 ethtools/src/lib.rs rename {ethtools => util}/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 (100%) rename {ethtools => util}/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf (100%) rename ethtools/src/geth_keys.rs => util/src/keys/geth_import.rs (91%) diff --git a/ethtools/Cargo.toml b/ethtools/Cargo.toml deleted file mode 100644 index 87e101b4d..000000000 --- a/ethtools/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -description = "Ethcore Ethereum tools" -homepage = "http://ethcore.io" -license = "GPL-3.0" -name = "ethtools" -version = "0.9.99" -authors = ["Ethcore "] - -[dependencies] -ethcore-util = { path = "../util" } -rustc-serialize = "0.3" -ethcore-devtools = { path = "../devtools" } -log = "0.3" diff --git a/ethtools/README.md b/ethtools/README.md deleted file mode 100644 index f3e852ff5..000000000 --- a/ethtools/README.md +++ /dev/null @@ -1 +0,0 @@ -# ethtools diff --git a/ethtools/src/lib.rs b/ethtools/src/lib.rs deleted file mode 100644 index 4cf365f5f..000000000 --- a/ethtools/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Ethereum Tools Library - -extern crate ethcore_util as util; -extern crate rustc_serialize; -extern crate ethcore_devtools as devtools; -#[macro_use] extern crate log; - -pub mod geth_keys; diff --git a/ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 b/util/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 similarity index 100% rename from ethtools/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 rename to util/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 diff --git a/ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf b/util/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf similarity index 100% rename from ethtools/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf rename to util/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 233b8b974..7fe6fb1ee 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -618,6 +618,8 @@ impl KeyDirectory { Err(_) => Err(KeyFileLoadError::ParseError(KeyFileParseError::InvalidJson)) } } + + } diff --git a/ethtools/src/geth_keys.rs b/util/src/keys/geth_import.rs similarity index 91% rename from ethtools/src/geth_keys.rs rename to util/src/keys/geth_import.rs index 1a6fb75d4..61df88589 100644 --- a/ethtools/src/geth_keys.rs +++ b/util/src/keys/geth_import.rs @@ -16,16 +16,9 @@ //! Geth keys import/export tool -use util::hash::*; -use util::keys::store::SecretStore; -use util::keys::directory::KeyFileContent; -use std::path::{Path, PathBuf}; -use std::result::*; -use std::fs; -use std::str::FromStr; -use std::io; -use std::io::Read; -use rustc_serialize::json::Json; +use common::*; +use keys::store::SecretStore; +use keys::directory::KeyFileContent; /// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)` pub fn enumerate_geth_keys(path: &Path) -> Result, io::Error> { @@ -86,6 +79,7 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) /// Imports all geth keys in the directory pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> { + use std::path::PathBuf; let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory)); for &(ref address, ref file_path) in geth_files.iter() { let mut path = PathBuf::new(); @@ -101,10 +95,9 @@ pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: #[cfg(test)] mod tests { use super::*; - use std::path::Path; - use util::hash::*; - use util::keys::store::SecretStore; - use std::str::FromStr; + use common::*; + use keys::store::SecretStore; + #[test] fn can_enumerate() { @@ -136,7 +129,7 @@ mod tests { #[test] fn imports_as_scrypt_keys() { - use util::keys::directory::{KeyDirectory, KeyFileKdf}; + use keys::directory::{KeyDirectory, KeyFileKdf}; let temp = ::devtools::RandomTempPath::create_dir(); { let mut secret_store = SecretStore::new_in(temp.as_path()); @@ -158,8 +151,7 @@ mod tests { #[test] fn can_decrypt_with_imported() { - use util::keys::store::EncryptedHashMap; - use util::bytes::*; + use keys::store::EncryptedHashMap; let temp = ::devtools::RandomTempPath::create_dir(); let mut secret_store = SecretStore::new_in(temp.as_path()); diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index fd52136d7..b9c9dcb08 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -18,3 +18,4 @@ pub mod directory; pub mod store; +mod geth_import; diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 3c2aef7c3..3b1ca4727 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -75,6 +75,20 @@ impl SecretStore { } } + /// trys to import keys in the known locations + pub fn try_import_existing(&mut self) { + use std::path::PathBuf; + use keys::geth_import; + + let mut import_path = PathBuf::new(); + import_path.push(::std::env::home_dir().expect("Failed to get home dir")); + import_path.push(".ethereum"); + import_path.push("keystore"); + if let Err(e) = geth_import::import_geth_keys(self, &import_path) { + warn!(target: "sstore", "Error retrieving geth keys: {:?}", e) + } + } + /// Lists all accounts and corresponding key ids pub fn accounts(&self) -> Result, ::std::io::Error> { let accounts = try!(self.directory.list()).iter().map(|key_id| self.directory.get(key_id)) From 394e57d3ce17f5a1c7a1b788202d2eb33ce00750 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 24 Feb 2016 10:23:25 +0100 Subject: [PATCH 187/753] removed unnecessary maps --- ethcore/src/chainfilter/chainfilter.rs | 6 ++---- ethcore/src/client.rs | 18 ++++++------------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs index e0a281f12..fb6df877a 100644 --- a/ethcore/src/chainfilter/chainfilter.rs +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -110,9 +110,8 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource // map them to offsets .map(|li| li.index * level_size) // get all blocks that may contain our bloom - .map(|off| self.blocks(bloom, from_block, to_block, level - 1, off)) // filter existing ones - .filter_map(|x| x) + .filter_map(|off| self.blocks(bloom, from_block, to_block, level - 1, off)) // flatten nested structures .flat_map(|v| v) .collect(); @@ -161,9 +160,8 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource self.indexer.lower_level_bloom_indexes(&index) .into_iter() // get blooms - .map(bloom_at) // filter existing ones - .filter_map(|b| b) + .filter_map(bloom_at) // BitOr all of them .fold(H2048::new(), |acc, bloom| acc | bloom) }; diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 18ce28c6b..9244c26fc 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -482,8 +482,7 @@ impl BlockChainClient for Client { fn logs(&self, filter: Filter) -> Vec { let mut blocks = filter.bloom_possibilities().iter() - .map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone())) - .filter_map(|m| m) + .filter_map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone())) .flat_map(|m| m) // remove duplicate elements .collect::>() @@ -493,17 +492,14 @@ impl BlockChainClient for Client { blocks.sort(); blocks.into_iter() - .map(|number| self.chain.read().unwrap().block_hash(number).map(|hash| (number, hash))) - .filter_map(|m| m) - .map(|(number, hash)| self.chain.read().unwrap().block_receipts(&hash).map(|r| (number, hash, r.receipts))) - .filter_map(|m| m) - .map(|(number, hash, receipts)| self.chain.read().unwrap().block(&hash).map(|ref b| (number, hash, receipts, BlockView::new(b).transaction_hashes()))) - .filter_map(|m| m) - .map(|(number, hash, receipts, hashes)| { + .filter_map(|number| self.chain.read().unwrap().block_hash(number).map(|hash| (number, hash))) + .filter_map(|(number, hash)| self.chain.read().unwrap().block_receipts(&hash).map(|r| (number, hash, r.receipts))) + .filter_map(|(number, hash, receipts)| self.chain.read().unwrap().block(&hash).map(|ref b| (number, hash, receipts, BlockView::new(b).transaction_hashes()))) + .flat_map(|(number, hash, receipts, hashes)| { let mut log_index = 0; receipts.into_iter() .enumerate() - .map(|(index, receipt)| { + .flat_map(|(index, receipt)| { log_index += receipt.logs.len(); receipt.logs.into_iter() .enumerate() @@ -518,11 +514,9 @@ impl BlockChainClient for Client { }) .collect::>() }) - .flat_map(|m| m) .collect::>() }) - .flat_map(|m| m) .collect() } } From ca251215cf871e82bdd8f7a7f6a265f201e635f5 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 24 Feb 2016 10:35:05 +0100 Subject: [PATCH 188/753] simplified filter iterators --- ethcore/src/filter.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/ethcore/src/filter.rs b/ethcore/src/filter.rs index f5f9135d6..95c5687a7 100644 --- a/ethcore/src/filter.rs +++ b/ethcore/src/filter.rs @@ -57,30 +57,26 @@ impl Filter { self.topics.iter().fold(blooms, | bs, topic | match *topic { None => bs, - Some(ref topics) => bs.into_iter().map(|bloom| { + Some(ref topics) => bs.into_iter().flat_map(|bloom| { topics.into_iter().map(|topic| { let mut b = bloom.clone(); b.shift_bloomed(&topic.sha3()); b }).collect::>() - }).flat_map(|m| m).collect() + }).collect() }) } /// Returns true if given log entry matches filter. pub fn matches(&self, log: &LogEntry) -> bool { let matches = match self.address { - Some(ref addresses) if !addresses.is_empty() => addresses.iter().fold(false, |res, address| { - res || &log.address == address - }), + Some(ref addresses) if !addresses.is_empty() => addresses.iter().any(|address| &log.address == address), _ => true }; - matches && self.topics.iter().enumerate().fold(true, |res, (i, topic)| match *topic { - Some(ref topics) if !topics.is_empty() => res && topics.iter().fold(false, | acc, topic | { - acc || log.topics.get(i) == Some(topic) - }), - _ => res, + matches && self.topics.iter().enumerate().all(|(i, topic)| match *topic { + Some(ref topics) if !topics.is_empty() => topics.iter().any(|topic| log.topics.get(i) == Some(topic)), + _ => true }) } } From da936d2e9490cf293c9ac17faa569e2dc1c610ca Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 24 Feb 2016 10:45:17 +0100 Subject: [PATCH 189/753] removed unused umports --- ethcore/src/blockchain.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 2b812e92d..0e14b0502 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -817,8 +817,6 @@ mod tests { use blockchain::{BlockProvider, BlockChain}; use tests::helpers::*; use devtools::*; - use views::BlockView; - use util::uint::U256; #[test] fn valid_tests_extra32() { From d3fe3f26918c676353f96461a94ac6a8aa6fceb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 24 Feb 2016 10:55:34 +0100 Subject: [PATCH 190/753] Client refactoring [WIP] --- ethcore/src/block_queue.rs | 23 ++++--- ethcore/src/client.rs | 124 ++++++++++++++++++++----------------- 2 files changed, 81 insertions(+), 66 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index c39f158f0..b802e3c26 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -285,19 +285,22 @@ impl BlockQueue { } /// Mark given block and all its children as bad. Stops verification. - pub fn mark_as_bad(&mut self, hash: &H256) { + pub fn mark_as_bad(&mut self, hashes: &[H256]) { let mut verification_lock = self.verification.lock().unwrap(); let mut verification = verification_lock.deref_mut(); - verification.bad.insert(hash.clone()); - self.processing.write().unwrap().remove(&hash); let mut new_verified = VecDeque::new(); - for block in verification.verified.drain(..) { - if verification.bad.contains(&block.header.parent_hash) { - verification.bad.insert(block.header.hash()); - self.processing.write().unwrap().remove(&block.header.hash()); - } - else { - new_verified.push_back(block); + + for hash in hashes { + verification.bad.insert(hash.clone()); + self.processing.write().unwrap().remove(&hash); + for block in verification.verified.drain(..) { + if verification.bad.contains(&block.header.parent_hash) { + verification.bad.insert(block.header.hash()); + self.processing.write().unwrap().remove(&block.header.hash()); + } + else { + new_verified.push_back(block); + } } } verification.verified = new_verified; diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 87dba3dd5..3c44b97bf 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -259,70 +259,73 @@ impl Client { last_hashes } + fn check_and_close_block(&self, block: &PreVerifiedBlock) -> Result { + let engine = self.engine.deref().deref(); + let header = &block.header; + let header_hash = block.header.hash(); + + // Verify Block Family + let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); + if let Err(e) = verify_family_result { + warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); + return Err(()); + }; + + // Check if Parent is in chain + let chain_has_parent = self.chain.read().unwrap().block_header(&header.parent_hash); + if let None = chain_has_parent { + warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); + return Err(()); + }; + + // Enact Verified Block + let parent = chain_has_parent.unwrap(); + let last_hashes = self.build_last_hashes(header); + let db = self.state_db.lock().unwrap().clone(); + + let enact_result = enact_verified(&block, engine, db, &parent, last_hashes); + if let Err(e) = enact_result { + warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); + return Err(()); + }; + + // Final Verification + let closed_block = enact_result.unwrap(); + if let Err(e) = verify_block_final(&header, closed_block.block().header()) { + warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); + return Err(()); + } + + Ok(closed_block) + } + /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self, io: &IoChannel) -> usize { let max_blocks_to_import = 128; - let mut imported = 0; let mut good_blocks = Vec::with_capacity(max_blocks_to_import); let mut bad_blocks = HashSet::new(); - let engine = self.engine.deref().deref(); let _import_lock = self.import_lock.lock(); let blocks = self.block_queue.write().unwrap().drain(max_blocks_to_import); for block in blocks { - let header = &block.header; - let header_hash = block.header.hash(); - let bad_contains_parent = bad_blocks.contains(&header.parent_hash); + let header = block.header; - let mark_block_as_bad = || { - self.block_queue.write().unwrap().mark_as_bad(&header_hash); - bad_blocks.insert(header_hash); - }; - - if bad_contains_parent { - mark_block_as_bad(); + if bad_blocks.contains(&header.parent_hash) { + bad_blocks.insert(header.hash()); continue; } - // Verify Block Family - let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); - if let Err(e) = verify_family_result { - warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - mark_block_as_bad(); - break; - }; - // Check if Parent is in chain - let chain_has_parent = self.chain.read().unwrap().block_header(&header.parent_hash); - if let None = chain_has_parent { - warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); - mark_block_as_bad(); - break; - }; - - // Enact Verified Block - let parent = chain_has_parent.unwrap(); - let last_hashes = self.build_last_hashes(header); - let db = self.state_db.lock().unwrap().clone(); - - let enact_result = enact_verified(&block, engine, db, &parent, &last_hashes); - if let Err(e) = enact_result { - warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - mark_block_as_bad(); - break; - }; - - // Final Verification - let enact_result = enact_result.unwrap(); - if let Err(e) = verify_block_final(&header, enact_result.block().header()) { - warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - mark_block_as_bad(); + let closed_block = self.check_and_close_block(&block); + if let Err(_) = closed_block { + bad_blocks.insert(header.hash()); break; } // Insert block + let closed_block = closed_block.unwrap(); self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? good_blocks.push(header.hash()); @@ -335,24 +338,33 @@ impl Client { }; // Commit results - let commit_result = enact_result.drain().commit(header.number(), &header.hash(), ancient); - if let Err(e) = commit_result { - warn!(target: "client", "State DB commit failed: {:?}", e); - break; - } + closed_block.drain() + .commit(header.number(), &header.hash(), ancient) + .expect("State DB commit failed."); self.report.write().unwrap().accrue_block(&block); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); - imported += 1; } - self.block_queue.write().unwrap().mark_as_good(&good_blocks); - if !good_blocks.is_empty() && self.block_queue.read().unwrap().queue_info().is_empty() { - io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { - good: good_blocks, - bad: bad_blocks.into_iter().collect(), - })).unwrap(); + let imported = good_blocks.len(); + let bad_blocks = bad_blocks.into_iter().collect::>(); + + { + let block_queue = self.block_queue.write().unwrap(); + block_queue.mark_as_bad(&bad_blocks); + block_queue.mark_as_good(&good_blocks); } + + { + let block_queue = self.block_queue.read().unwrap(); + if !good_blocks.is_empty() && block_queue.queue_info().is_empty() { + io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { + good: good_blocks, + bad: bad_blocks, + })).unwrap(); + } + } + imported } From d914a27bdfd2ac69035f129600ee719d7337794d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 24 Feb 2016 11:17:25 +0100 Subject: [PATCH 191/753] Removing lifetimes from Blocks --- ethcore/src/block.rs | 38 +++++++++++++++++----------------- ethcore/src/client.rs | 6 ++---- ethcore/src/ethereum/ethash.rs | 4 ++-- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index a1194c665..9051b6d9a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -146,18 +146,18 @@ impl IsBlock for ExecutedBlock { /// /// It's a bit like a Vec, eccept that whenever a transaction is pushed, we execute it and /// maintain the system `state()`. We also archive execution receipts in preparation for later block creation. -pub struct OpenBlock<'x, 'y> { +pub struct OpenBlock<'x> { block: ExecutedBlock, engine: &'x Engine, - last_hashes: &'y LastHashes, + last_hashes: LastHashes, } /// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, /// and collected the uncles. /// /// There is no function available to push a transaction. If you want that you'll need to `reopen()` it. -pub struct ClosedBlock<'x, 'y> { - open_block: OpenBlock<'x, 'y>, +pub struct ClosedBlock<'x> { + open_block: OpenBlock<'x>, uncle_bytes: Bytes, } @@ -169,9 +169,9 @@ pub struct SealedBlock { uncle_bytes: Bytes, } -impl<'x, 'y> OpenBlock<'x, 'y> { +impl<'x> OpenBlock<'x> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new(engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes, author: Address, extra_data: Bytes) -> Self { + pub fn new(engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { let mut r = OpenBlock { block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), engine: engine, @@ -259,7 +259,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> { } /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. - pub fn close(self) -> ClosedBlock<'x, 'y> { + pub fn close(self) -> ClosedBlock<'x> { let mut s = self; s.engine.on_close_block(&mut s.block); s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect()); @@ -275,16 +275,16 @@ impl<'x, 'y> OpenBlock<'x, 'y> { } } -impl<'x, 'y> IsBlock for OpenBlock<'x, 'y> { +impl<'x> IsBlock for OpenBlock<'x> { fn block(&self) -> &ExecutedBlock { &self.block } } -impl<'x, 'y> IsBlock for ClosedBlock<'x, 'y> { +impl<'x> IsBlock for ClosedBlock<'x> { fn block(&self) -> &ExecutedBlock { &self.open_block.block } } -impl<'x, 'y> ClosedBlock<'x, 'y> { - fn new(open_block: OpenBlock<'x, 'y>, uncle_bytes: Bytes) -> Self { +impl<'x> ClosedBlock<'x> { + fn new(open_block: OpenBlock<'x>, uncle_bytes: Bytes) -> Self { ClosedBlock { open_block: open_block, uncle_bytes: uncle_bytes, @@ -307,7 +307,7 @@ impl<'x, 'y> ClosedBlock<'x, 'y> { } /// Turn this back into an `OpenBlock`. - pub fn reopen(self) -> OpenBlock<'x, 'y> { self.open_block } + pub fn reopen(self) -> OpenBlock<'x> { self.open_block } /// Drop this object and return the underlieing database. pub fn drain(self) -> JournalDB { self.open_block.block.state.drop().1 } @@ -332,7 +332,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact<'x, 'y>(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact<'x>(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> { { if ::log::max_log_level() >= ::log::LogLevel::Trace { let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce()); @@ -350,20 +350,20 @@ pub fn enact<'x, 'y>(header: &Header, transactions: &[SignedTransaction], uncles } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact_bytes<'x>(block_bytes: &[u8], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> { let block = BlockView::new(block_bytes); let header = block.header(); enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified<'x, 'y>(block: &PreVerifiedBlock, engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact_verified<'x>(block: &PreVerifiedBlock, engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> { let view = BlockView::new(&block.bytes); enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: &LastHashes) -> Result { +pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(header.seal()))) } @@ -384,7 +384,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(&mut db); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let b = b.close(); let _ = b.seal(vec![]); } @@ -398,14 +398,14 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(&mut db); - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(&mut db); - let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, &vec![genesis_header.hash()]).unwrap(); + let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 3c44b97bf..2d57fbc3d 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -262,7 +262,6 @@ impl Client { fn check_and_close_block(&self, block: &PreVerifiedBlock) -> Result { let engine = self.engine.deref().deref(); let header = &block.header; - let header_hash = block.header.hash(); // Verify Block Family let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); @@ -310,14 +309,13 @@ impl Client { let blocks = self.block_queue.write().unwrap().drain(max_blocks_to_import); for block in blocks { - let header = block.header; + let header = &block.header; if bad_blocks.contains(&header.parent_hash) { bad_blocks.insert(header.hash()); continue; } - let closed_block = self.check_and_close_block(&block); if let Err(_) = closed_block { bad_blocks.insert(header.hash()); @@ -350,7 +348,7 @@ impl Client { let bad_blocks = bad_blocks.into_iter().collect::>(); { - let block_queue = self.block_queue.write().unwrap(); + let mut block_queue = self.block_queue.write().unwrap(); block_queue.mark_as_bad(&bad_blocks); block_queue.mark_as_good(&good_blocks); } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 8c411e7f0..54f02524d 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -282,7 +282,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(&mut db); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -295,7 +295,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(&mut db); let last_hashes = vec![genesis_header.hash()]; - let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let mut uncle = Header::new(); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); uncle.author = uncle_author.clone(); From 365218590c0261abd8407475c9b3221bec0040df Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 24 Feb 2016 11:19:27 +0100 Subject: [PATCH 192/753] fixed travis --org GH_TOKEN --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ab9a08b9..167dc2622 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,9 +60,8 @@ after_success: | git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages env: global: - - secure: 3sUjNi9mhdL5h1GTm8LONnDN/SYvUHT+WSkMl93h3nYiLCQXk8eZaPS98AS7oOaTsfW4UvnwckVFCFl49ttInsv4cd/TkAxmrJHe6kPyS9/4NWUdmP8BjicbBvL/ioSdXMECMEYzPDLV+I3KhtC2LcB6ceDEl/XwMOJlzbGf7RbtcXGVQgMLqSYY1YKjQA4vbT5nFgIS/sZu3Z9yFgN0GafnihKcizqoHhdJjs/zxmX+qJepnC6o3V6KcFnS7QHhM1JOr85twE6S422UlvNaEb5ovwLPqmOl5+fA+6shbx4AxFTY6E9Iors+OVY/JliFhrqOdCt0i2P1FUHN4kbGZQkf0rphN/ZOI2uKNFTOyXiPvppfo/ZemKmcqkwkqP9+lf5QqYmtE6hsAYagxn49xJZILl8tAYbdqxF5gxa+TEVrfsBFtz/Sv3q8QhKQNPAmjEcKyMatyEreLUIFEpFTGIco8jN4eXeSoLRdJ+Z75ihttfQWhNfUDgNL30iQLy0AgFSsh/cyb5M8y9lxrGDzDTogvaiKGwr/V45sPkcXWCkmOgMdINqBB6ZtdL3bGHdyjmYj+y3btjf3aP11k++BL0fXIaKn25aS/p/9iyGb1FyGCM03o4ZRQ3YhTOvfMRfRGf6nWbaMx9upv8o5ShSdysewhrnh3082r7u896ny1Ho= - - secure: 0/FeVvFl3AhBW0TCPoujY9zOAYoUNMlAz3XjC04vlc4Ksfx0lGU3KFi97LlALxMWV0lfwQc7ixSe2vTgQVQuLVSU9XEW40fQgEjJlmLca2RcRx1kfzJDypuWSiCME7MWmLPH0ac4COdTDS1z5WGggv5YB7GQPCzFvcmOOaPYtF29ngCtkyB2HmNkY/W3omHFEk7Si6bsmOSHZiOAhivPl6ixnGpFyTEKPyraMMqPIj5rbEGkzgeLTiXf2ur143n/tnSr8tmP1MfQi9yS8/ONidMqnxUeuLkeNnb82zj9pVJhVXq0xF44WXJ8Za1jm0ByiTakgqpm8Juk822qjvtNulJ1XZW/fyZQZaN1dy3uq5Ud3W8wS9M7VIVl8CoXozzDpIsdPeUAtkAxeHBsZqL1vAH2yC1YJA7HPySMYzCjYqkJ2r62xYk0gXmNXphfU+F/X/rHzHsTMJPONJ54HQwu12m7zVlKIYBGHgEXg/HAM/g4ljUzl6WWR/nHH/tQM8ND/8FpHluJSZJWacq/1QNhVdTq2x6cqws2fs5A7nVpccR9+6RRgYgv6+YS2LxvFzByuZveGGoKif+uMECXN876j40araUqU528Yz9i8bHJlnM3coRBndaLNWByLcUyXCB9r9IUosUu41rr+L2mVzkSDm0GicuNCzqvzYQ9Q6QY4uQ= - - secure: DglvLR27MrBKQO/8s7ZfGqfimXk1Iq5MreCTc+ZkWMkZ0sDP76YBUPq5j25hcg0Z09z09O2Q5OUOyYkhVD4AnRjoRLUplHdpDE9CBSz2vUGpMpzhgAqzBc6SDsEmWU2JlAPBraIODXQdP/Qo6tYY4zn3vwd/VFKo27GTb5b60WAkTVvT/0YPWycEXFIa7sNMgjNI0EnT+Se5USDYwb6MM1T9JxJot0q3WtOnsVyroCHJp4QDicpS8eQIu3Tl+SLE4d0EoJ4YYLOI+jWOybipuO1xM1xlHq/gpWfjKqbJh24xtAds524dN7ujfjAhyO2zQbuTOfi7QVOj/Go0tGYxNxobR4pYG783Aiq3Quj0GzSrLEAatkk5tGOcuVJ98EYIg3WPJuC93waTTXcS0xDyy09XHxWxZ/5PiXorRZjpHvnZfRF0X4Mus6jUJ7hqDuOUiF5BI1RHomHvJQQHUrLdmh7OHyrer3YUpKRs65tww6H+VM+lKNa3MnMkB5+or/co14svs7I4pni9S+aZg//bwuxGVXchK6bjLCP1X99Ar4fA5EGsTVdjp3PRqutM/P3RqNGkwTczat/PNZ8fFAD9y7pDs2L6YkqpflTC9d6vKTSl6gORGw6ltLUJs23ON6xRNIBMw1cXp67wN57vF46TPt1i3ZlIQsYn0pAVNKavbZE= + # GH_TOKEN + - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= deploy: provider: releases From d51942e59de4808c4bc6cd2ac3a48bec0635744a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 24 Feb 2016 14:36:41 +0300 Subject: [PATCH 193/753] fix issue with starting requested block number was not included itself --- sync/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 5c79e08b6..9d550f199 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -927,13 +927,13 @@ impl ChainSync { if reverse { number = min(last, number); } else { - number = max(1, number); + number = max(0, number); } let max_count = min(MAX_HEADERS_TO_SEND, max_headers); let mut count = 0; let mut data = Bytes::new(); let inc = (skip + 1) as BlockNumber; - while number <= last && number > 0 && count < max_count { + while number <= last && number >= 0 && count < max_count { if let Some(mut hdr) = io.chain().block_header(BlockId::Number(number)) { data.append(&mut hdr); count += 1; From d4ad673d645d6205be458ec5931ff3ac8d342edf Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 24 Feb 2016 15:01:45 +0300 Subject: [PATCH 194/753] tested out --- sync/src/chain.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 9d550f199..f76978bda 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -933,13 +933,13 @@ impl ChainSync { let mut count = 0; let mut data = Bytes::new(); let inc = (skip + 1) as BlockNumber; - while number <= last && number >= 0 && count < max_count { + while number <= last && count < max_count { if let Some(mut hdr) = io.chain().block_header(BlockId::Number(number)) { data.append(&mut hdr); count += 1; } if reverse { - if number <= inc { + if number <= inc || number == 0 { break; } number -= inc; @@ -1542,4 +1542,53 @@ mod tests { let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); assert!(result.is_ok()); } + + #[test] + fn returns_requested_block_headers() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, false); + let mut queue = VecDeque::new(); + let io = TestIo::new(&mut client, &mut queue, None); + + let mut rlp = RlpStream::new_list(4); + rlp.append(&0u64); + rlp.append(&10u64); + rlp.append(&0u64); + rlp.append(&0u64); + let data = rlp.out(); + + let response = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&data)); + + assert!(response.is_ok()); + let (_, rlp_stream) = response.unwrap().unwrap(); + let response_data = rlp_stream.out(); + let rlp = UntrustedRlp::new(&response_data); + assert!(rlp.at(0).is_ok()); + assert!(rlp.at(9).is_ok()); + } + + #[test] + fn returns_requested_block_headers_reverse() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, false); + let mut queue = VecDeque::new(); + let io = TestIo::new(&mut client, &mut queue, None); + + let mut rlp = RlpStream::new_list(4); + rlp.append(&15u64); + rlp.append(&15u64); + rlp.append(&0u64); + rlp.append(&1u64); + let data = rlp.out(); + + let response = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&data)); + + assert!(response.is_ok()); + let (_, rlp_stream) = response.unwrap().unwrap(); + let response_data = rlp_stream.out(); + let rlp = UntrustedRlp::new(&response_data); + assert!(rlp.at(0).is_ok()); + assert!(rlp.at(14).is_ok()); + assert!(!rlp.at(15).is_ok()); + } } From 0318907fb39e6535a69524e0a6ec419063695c83 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 24 Feb 2016 14:16:05 +0100 Subject: [PATCH 195/753] rpc eth_getFilterChanges returns new blocks, implemented eth_uninstallFilter --- ethcore/src/client.rs | 8 ++++++++ rpc/src/v1/impls/eth.rs | 21 ++++++++++++++++++--- sync/src/tests/helpers.rs | 4 ++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 9244c26fc..3a1a80141 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -114,6 +114,9 @@ pub trait BlockChainClient : Sync + Send { /// Get block total difficulty. fn block_total_difficulty(&self, id: BlockId) -> Option; + /// Get block hash. + fn block_hash(&self, id: BlockId) -> Option; + /// Get address code. fn code(&self, address: &Address) -> Option; @@ -416,6 +419,11 @@ impl BlockChainClient for Client { Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) } + fn block_hash(&self, id: BlockId) -> Option { + let chain = self.chain.read().unwrap(); + Self::block_hash(&chain, id) + } + fn code(&self, address: &Address) -> Option { self.state().code(address) } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 153a51216..e2cc1a5c3 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -267,11 +267,18 @@ impl EthFilter for EthFilterClient { None => Ok(Value::Array(vec![] as Vec)), Some(info) => match info.filter { PollFilter::Block => { - //unimplemented!() - to_value(&self.client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) + let current_number = self.client.chain_info().best_block_number; + let hashes = (info.block_number..current_number).into_iter() + .map(BlockId::Number) + .filter_map(|id| self.client.block_hash(id)) + .collect::>(); + + self.polls.lock().unwrap().update_poll(&index.value(), current_number); + + to_value(&hashes) }, PollFilter::PendingTransaction => { - //unimplemented!() + // TODO: fix implementation to_value(&self.client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) }, PollFilter::Logs(mut filter) => { @@ -291,4 +298,12 @@ impl EthFilter for EthFilterClient { } }) } + + fn uninstall_filter(&self, params: Params) -> Result { + from_params::<(Index,)>(params) + .and_then(|(index,)| { + self.polls.lock().unwrap().remove_poll(&index.value()); + to_value(&true) + }) + } } diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 7f2928ccd..1d442f908 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -105,6 +105,10 @@ impl BlockChainClient for TestBlockChainClient { Some(U256::zero()) } + fn block_hash(&self, id: BlockId) -> Option { + unimplemented!(); + } + fn code(&self, _address: &Address) -> Option { unimplemented!(); } From 08647282dff3999353ba7dbcc8c6bac046b1245c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 24 Feb 2016 17:01:29 +0100 Subject: [PATCH 196/753] Fixing mark_as_bad implementation --- ethcore/res/ethereum/tests | 2 +- ethcore/src/block_queue.rs | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index f32954b3d..3116f85a4 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit f32954b3ddb5af2dc3dc9ec6d9a28bee848fdf70 +Subproject commit 3116f85a499ceaf4dfdc46726060fc056e2d7829 diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index b802e3c26..ff20021f2 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -287,20 +287,23 @@ impl BlockQueue { /// Mark given block and all its children as bad. Stops verification. pub fn mark_as_bad(&mut self, hashes: &[H256]) { let mut verification_lock = self.verification.lock().unwrap(); - let mut verification = verification_lock.deref_mut(); - let mut new_verified = VecDeque::new(); + let mut processing = self.processing.write().unwrap(); + let mut verification = verification_lock.deref_mut(); + + verification.bad.reserve(hashes.len()); for hash in hashes { verification.bad.insert(hash.clone()); - self.processing.write().unwrap().remove(&hash); - for block in verification.verified.drain(..) { - if verification.bad.contains(&block.header.parent_hash) { - verification.bad.insert(block.header.hash()); - self.processing.write().unwrap().remove(&block.header.hash()); - } - else { - new_verified.push_back(block); - } + processing.remove(&hash); + } + + let mut new_verified = VecDeque::new(); + for block in verification.verified.drain(..) { + if verification.bad.contains(&block.header.parent_hash) { + verification.bad.insert(block.header.hash()); + processing.remove(&block.header.hash()); + } else { + new_verified.push_back(block); } } verification.verified = new_verified; From dd8652dbf41715dcb44e7fa4c835634b99c1d771 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 24 Feb 2016 21:17:29 +0300 Subject: [PATCH 197/753] u256 to inline assembly opt --- util/benches/bigint.rs | 37 +++++++++++++++++ util/src/lib.rs | 1 + util/src/uint.rs | 90 ++++++++++++++++++++++++++++++------------ 3 files changed, 102 insertions(+), 26 deletions(-) create mode 100644 util/benches/bigint.rs diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs new file mode 100644 index 000000000..6ba30d88c --- /dev/null +++ b/util/benches/bigint.rs @@ -0,0 +1,37 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! benchmarking for rlp +//! should be started with: +//! ```bash +//! multirust run nightly cargo bench +//! ``` + +#![feature(test)] + +extern crate test; +extern crate ethcore_util; + +use test::{Bencher, black_box}; +use ethcore_util::uint::*; + +#[bench] +fn u256_first_degree(b: &mut test::Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256::zero(), |old, new| { old.overflowing_add(U256::from(new)).0 }) + }); +} diff --git a/util/src/lib.rs b/util/src/lib.rs index 2b7438cf3..1f04240dc 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -16,6 +16,7 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", feature(asm))] #![cfg_attr(feature="dev", plugin(clippy))] // Clippy settings diff --git a/util/src/uint.rs b/util/src/uint.rs index 6490cbd9b..8266aff42 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -51,6 +51,64 @@ macro_rules! impl_map_from { } } +macro_rules! overflowing_add_regular { + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + let mut ret = [0u64; $n_words]; + let mut carry = [0u64; $n_words]; + let mut b_carry = false; + let mut overflow = false; + + for i in 0..$n_words { + ret[i] = me[i].wrapping_add(you[i]); + + if ret[i] < me[i] { + if i < $n_words - 1 { + carry[i + 1] = 1; + b_carry = true; + } else { + overflow = true; + } + } + } + if b_carry { + let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow); + (ret, overflow) + } else { + ($name(ret), overflow) + } + }) +} + +macro_rules! overflowing_add_u256_asm { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 4] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + unsafe { + asm!(" + xor %al, %al + adc $9, %r8 + adc $10, %r9 + adc $11, %r10 + adc $12, %r11 + adc $$0, %al" + : "={r8}"(result[0]), "={r9}"(result[1]), "={r10}"(result[2]), "={r11}"(result[3]), "={al}"(overflow) + : "{r8}"(self_t[0]), "{r9}"(self_t[1]), "{r10}"(self_t[2]), "{r11}"(self_t[3]), "m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]) + : + : + ); + } + (U256(result), overflow != 0) + }); + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( + overflowing_add_regular!($name, $n_words, $self_expr, $other) + ) +} + macro_rules! overflowing { ($op: expr, $overflow: expr) => ( { @@ -297,32 +355,14 @@ macro_rules! construct_uint { (res, overflow) } + #[cfg(all(feature = "dev", target_arch = "x86_64"))] fn overflowing_add(self, other: $name) -> ($name, bool) { - let $name(ref me) = self; - let $name(ref you) = other; - let mut ret = [0u64; $n_words]; - let mut carry = [0u64; $n_words]; - let mut b_carry = false; - let mut overflow = false; + overflowing_add_u256_asm!($name, $n_words, self, other) + } - for i in 0..$n_words { - ret[i] = me[i].wrapping_add(you[i]); - - if ret[i] < me[i] { - if i < $n_words - 1 { - carry[i + 1] = 1; - b_carry = true; - } else { - overflow = true; - } - } - } - if b_carry { - let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow); - (ret, overflow) - } else { - ($name(ret), overflow) - } + #[cfg(not(all(feature = "dev", target_arch = "x86_64")))] + fn overflowing_add(self, other: $name) -> ($name, bool) { + overflowing_add_regular!($name, $n_words, self, other) } fn overflowing_sub(self, other: $name) -> ($name, bool) { @@ -1171,8 +1211,6 @@ mod tests { ); } - - #[test] #[should_panic] pub fn uint256_mul_overflow_panic() { From 476bb85d414ab5ae0ee1d67435757a517a3ff430 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 24 Feb 2016 21:36:31 +0300 Subject: [PATCH 198/753] r m/r + setc/xor --- util/src/uint.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 8266aff42..db8792592 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -91,13 +91,13 @@ macro_rules! overflowing_add_u256_asm { unsafe { asm!(" xor %al, %al - adc $9, %r8 - adc $10, %r9 - adc $11, %r10 - adc $12, %r11 - adc $$0, %al" - : "={r8}"(result[0]), "={r9}"(result[1]), "={r10}"(result[2]), "={r11}"(result[3]), "={al}"(overflow) - : "{r8}"(self_t[0]), "{r9}"(self_t[1]), "{r10}"(self_t[2]), "{r11}"(self_t[3]), "m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]) + adc $9, $0 + adc $10, $1 + adc $11, $2 + adc $12, $3 + adc $$0, %al" + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) : : ); From 7821505139c32d8326dae60efe9b6b63e8e7530f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 24 Feb 2016 23:08:21 +0300 Subject: [PATCH 199/753] sub x64 optimize --- util/benches/bigint.rs | 11 +++++++++- util/src/uint.rs | 49 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 6ba30d88c..524d31508 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -29,9 +29,18 @@ use test::{Bencher, black_box}; use ethcore_util::uint::*; #[bench] -fn u256_first_degree(b: &mut test::Bencher) { +fn u256_add(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); (0..n).fold(U256::zero(), |old, new| { old.overflowing_add(U256::from(new)).0 }) }); } + +#[bench] +fn u256_sub(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256::zero(), |old, new| { old.overflowing_add(U256::from(new)).0 }) + }); +} + diff --git a/util/src/uint.rs b/util/src/uint.rs index db8792592..147b83e42 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -41,6 +41,8 @@ use from_json::*; use rustc_serialize::hex::ToHex; use serde; +#[cfg_attr(x64_asm_optimizations, all(feature = "dev", target_arch = "x86_64"))] + macro_rules! impl_map_from { ($thing:ident, $from:ty, $to:ty) => { impl From<$from> for $thing { @@ -81,7 +83,7 @@ macro_rules! overflowing_add_regular { }) } -macro_rules! overflowing_add_u256_asm { +macro_rules! add_64x_optimized { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; @@ -90,12 +92,38 @@ macro_rules! overflowing_add_u256_asm { let overflow: u8; unsafe { asm!(" - xor %al, %al adc $9, $0 adc $10, $1 adc $11, $2 adc $12, $3 - adc $$0, %al" + setc %al" + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) + : + : + ); + } + (U256(result), overflow != 0) + }); + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( + overflowing_add_regular!($name, $n_words, $self_expr, $other) + ) +} + +macro_rules! sub_64x_optimized { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 4] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + unsafe { + asm!(" + sbb $9, %r8 + sbb $10, %r9 + sbb $11, %r10 + sbb $12, %r11 + setb %al" : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) : @@ -355,16 +383,23 @@ macro_rules! construct_uint { (res, overflow) } - #[cfg(all(feature = "dev", target_arch = "x86_64"))] + /// Optimized instructions + #[cfg(x64_asm_optimizations)] + #[inline] fn overflowing_add(self, other: $name) -> ($name, bool) { - overflowing_add_u256_asm!($name, $n_words, self, other) + add_64x_optimized!($name, $n_words, self, other) } - - #[cfg(not(all(feature = "dev", target_arch = "x86_64")))] + #[cfg(not(x64_asm_optimizations))] fn overflowing_add(self, other: $name) -> ($name, bool) { overflowing_add_regular!($name, $n_words, self, other) } + #[cfg(x64_asm_optimizations)] + #[inline] + fn overflowing_sub(self, other: $name) -> ($name, bool) { + sub_64x_optimized!($name, $n_words, self, other) + } + #[cfg(not(x64_asm_optimizations))] fn overflowing_sub(self, other: $name) -> ($name, bool) { let res = overflowing!((!other).overflowing_add(From::from(1u64))); let res = overflowing!(self.overflowing_add(res)); From cb3608c6d3558ad2d39c2151d26fefeb25e8ae90 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 24 Feb 2016 21:23:58 +0100 Subject: [PATCH 200/753] Limit download ahead --- ethcore/src/spec.rs | 6 ++++ parity/main.rs | 6 ++-- sync/src/chain.rs | 63 +++++++++++++++++++++++------------- sync/src/lib.rs | 26 ++++++++++++--- sync/src/range_collection.rs | 2 +- sync/src/tests/helpers.rs | 5 +-- 6 files changed, 76 insertions(+), 32 deletions(-) diff --git a/ethcore/src/spec.rs b/ethcore/src/spec.rs index 5714ca734..38a0dda53 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec.rs @@ -58,6 +58,8 @@ pub struct Spec { /// Known nodes on the network in enode format. pub nodes: Vec, + /// Network ID + pub network_id: U256, /// Parameters concerning operation of the specific engine we're using. /// Maps the parameter name to an RLP-encoded value. @@ -120,6 +122,9 @@ impl Spec { /// Get the known knodes of the network in enode format. pub fn nodes(&self) -> &Vec { &self.nodes } + /// Get the configured Network ID. + pub fn network_id(&self) -> U256 { self.network_id } + /// Get the header of the genesis block. pub fn genesis_header(&self) -> Header { Header { @@ -250,6 +255,7 @@ impl FromJson for Spec { engine_name: json["engineName"].as_string().unwrap().to_owned(), engine_params: json_to_rlp_map(&json["params"]), nodes: nodes, + network_id: U256::from_str(&json["params"]["networkID"].as_string().unwrap()[2..]).unwrap(), builtins: builtins, parent_hash: H256::from_str(&genesis["parentHash"].as_string().unwrap()[2..]).unwrap(), author: Address::from_str(&genesis["author"].as_string().unwrap()[2..]).unwrap(), diff --git a/parity/main.rs b/parity/main.rs index 1b6a59a93..e95f38f13 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -48,7 +48,7 @@ use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethcore::blockchain::CacheSize; -use ethsync::EthSync; +use ethsync::{EthSync, SyncConfig}; use docopt::Docopt; use daemonize::Daemonize; @@ -281,6 +281,8 @@ impl Configuration { let spec = self.spec(); let net_settings = self.net_settings(&spec); + let mut sync_config = SyncConfig::default(); + sync_config.network_id = spec.network_id(); // Build client let mut service = ClientService::start(spec, net_settings, &Path::new(&self.path())).unwrap(); @@ -288,7 +290,7 @@ impl Configuration { client.configure_cache(self.args.flag_cache_pref_size, self.args.flag_cache_max_size); // Sync - let sync = EthSync::register(service.network(), client); + let sync = EthSync::register(service.network(), sync_config, client); // Setup rpc if self.args.flag_jsonrpc { diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 5c79e08b6..bea17c177 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -40,6 +40,7 @@ use ethcore::block::Block; use io::SyncIo; use time; use std::option::Option; +use super::SyncConfig; impl ToUsize for BlockNumber { fn to_usize(&self) -> usize { @@ -80,9 +81,7 @@ const NODE_DATA_PACKET: u8 = 0x0e; const GET_RECEIPTS_PACKET: u8 = 0x0f; const RECEIPTS_PACKET: u8 = 0x10; -const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent - -const CONNECTION_TIMEOUT_SEC: f64 = 10f64; +const CONNECTION_TIMEOUT_SEC: f64 = 5f64; struct Header { /// Header data @@ -203,13 +202,17 @@ pub struct ChainSync { have_common_block: bool, /// Last propagated block number last_send_block_number: BlockNumber, + /// Max blocks to download ahead + max_download_ahead_blocks: usize, + /// Network ID + network_id: U256, } type RlpResponseResult = Result, PacketDecodeError>; impl ChainSync { /// Create a new instance of syncing strategy. - pub fn new() -> ChainSync { + pub fn new(config: SyncConfig) -> ChainSync { ChainSync { state: SyncState::NotSynced, starting_block: 0, @@ -226,6 +229,8 @@ impl ChainSync { syncing_difficulty: U256::from(0u64), have_common_block: false, last_send_block_number: 0, + max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), + network_id: config.network_id, } } @@ -275,7 +280,6 @@ impl ChainSync { self.starting_block = 0; self.highest_block = None; self.have_common_block = false; - io.chain().clear_queue(); self.starting_block = io.chain().chain_info().best_block_number; self.state = SyncState::NotSynced; } @@ -307,7 +311,7 @@ impl ChainSync { trace!(target: "sync", "Peer {} genesis hash not matched", peer_id); return Ok(()); } - if peer.network_id != NETWORK_ID { + if peer.network_id != self.network_id { io.disable_peer(peer_id); trace!(target: "sync", "Peer {} network id not matched", peer_id); return Ok(()); @@ -436,7 +440,7 @@ impl ChainSync { trace!(target: "sync", "Got body {}", n); } None => { - debug!(target: "sync", "Ignored unknown block body"); + trace!(target: "sync", "Ignored unknown/stale block body"); } } } @@ -608,7 +612,7 @@ impl ChainSync { self.request_headers_by_hash(io, peer_id, &peer_latest, 1, 0, false); } else if self.state == SyncState::Blocks && io.chain().block_status(BlockId::Hash(peer_latest)) == BlockStatus::Unknown { - self.request_blocks(io, peer_id); + self.request_blocks(io, peer_id, false); } } @@ -617,7 +621,7 @@ impl ChainSync { } /// Find some headers or blocks to download for a peer. - fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId) { + fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId, ignore_others: bool) { self.clear_peer_download(peer_id); if io.chain().queue_info().is_full() { @@ -637,28 +641,34 @@ impl ChainSync { let mut index: BlockNumber = 0; while index != items.len() as BlockNumber && needed_bodies.len() < MAX_BODIES_TO_REQUEST { let block = start + index; - if !self.downloading_bodies.contains(&block) && !self.bodies.have_item(&block) { + if ignore_others || (!self.downloading_bodies.contains(&block) && !self.bodies.have_item(&block)) { needed_bodies.push(items[index as usize].hash.clone()); needed_numbers.push(block); - self.downloading_bodies.insert(block); } index += 1; } } } if !needed_bodies.is_empty() { + let (head, _) = self.headers.range_iter().next().unwrap(); + if needed_numbers.first().unwrap() - head > self.max_download_ahead_blocks as BlockNumber { + trace!(target: "sync", "{}: Stalled download ({} vs {}), helping with downloading block bodies", peer_id, needed_numbers.first().unwrap(), head); + self.request_blocks(io, peer_id, true); + return; + } + self.downloading_bodies.extend(needed_numbers.iter()); replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers); self.request_bodies(io, peer_id, needed_bodies); } else { // check if need to download headers - let mut start = 0usize; + let mut start = 0; if !self.have_common_block { // download backwards until common block is found 1 header at a time let chain_info = io.chain().chain_info(); - start = chain_info.best_block_number as usize; + start = chain_info.best_block_number; if !self.headers.is_empty() { - start = min(start, self.headers.range_iter().next().unwrap().0 as usize - 1); + start = min(start, self.headers.range_iter().next().unwrap().0 - 1); } if start == 0 { self.have_common_block = true; //reached genesis @@ -669,6 +679,7 @@ impl ChainSync { if self.have_common_block { let mut headers: Vec = Vec::new(); let mut prev = self.current_base_block() + 1; + let head = self.headers.range_iter().next().map(|(h, _)| h); for (next, ref items) in self.headers.range_iter() { if !headers.is_empty() { break; @@ -679,9 +690,8 @@ impl ChainSync { } let mut block = prev; while block < next && headers.len() < MAX_HEADERS_TO_REQUEST { - if !self.downloading_headers.contains(&(block as BlockNumber)) { + if ignore_others || !self.downloading_headers.contains(&(block as BlockNumber)) { headers.push(block as BlockNumber); - self.downloading_headers.insert(block as BlockNumber); } block += 1; } @@ -689,17 +699,23 @@ impl ChainSync { } if !headers.is_empty() { - start = headers[0] as usize; + start = headers[0]; + if head.is_some() && start > head.unwrap() && start - head.unwrap() > self.max_download_ahead_blocks as BlockNumber { + trace!(target: "sync", "{}: Stalled download ({} vs {}), helping with downloading headers", peer_id, start, head.unwrap()); + self.request_blocks(io, peer_id, true); + return; + } let count = headers.len(); + self.downloading_headers.extend(headers.iter()); replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, headers); - assert!(!self.headers.have_item(&(start as BlockNumber))); - self.request_headers_by_number(io, peer_id, start as BlockNumber, count, 0, false); + assert!(!self.headers.have_item(&start)); + self.request_headers_by_number(io, peer_id, start, count, 0, false); } } else { // continue search for common block - self.downloading_headers.insert(start as BlockNumber); - self.request_headers_by_number(io, peer_id, start as BlockNumber, 1, 0, false); + self.downloading_headers.insert(start); + self.request_headers_by_number(io, peer_id, start, 1, 0, false); } } } @@ -891,7 +907,7 @@ impl ChainSync { let mut packet = RlpStream::new_list(5); let chain = io.chain().chain_info(); packet.append(&(PROTOCOL_VERSION as u32)); - packet.append(&NETWORK_ID); //TODO: network id + packet.append(&self.network_id); packet.append(&chain.total_difficulty); packet.append(&chain.best_block_hash); packet.append(&chain.genesis_hash); @@ -1221,6 +1237,7 @@ impl ChainSync { mod tests { use tests::helpers::*; use super::*; + use ::SyncConfig; use util::*; use super::{PeerInfo, PeerAsking}; use ethcore::header::*; @@ -1334,7 +1351,7 @@ mod tests { } fn dummy_sync_with_peer(peer_latest_hash: H256) -> ChainSync { - let mut sync = ChainSync::new(); + let mut sync = ChainSync::new(SyncConfig::default()); sync.peers.insert(0, PeerInfo { protocol_version: 0, diff --git a/sync/src/lib.rs b/sync/src/lib.rs index fd586409a..397a09f47 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -35,14 +35,14 @@ //! use std::sync::Arc; //! use util::network::{NetworkService, NetworkConfiguration}; //! use ethcore::client::Client; -//! use ethsync::EthSync; +//! use ethsync::{EthSync, SyncConfig}; //! use ethcore::ethereum; //! //! fn main() { //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let dir = env::temp_dir(); //! let client = Client::new(ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); -//! EthSync::register(&mut service, client); +//! EthSync::register(&mut service, SyncConfig::default(), client); //! } //! ``` @@ -60,6 +60,7 @@ use std::sync::*; use ethcore::client::Client; use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId}; use util::TimerToken; +use util::{U256, ONE_U256}; use chain::ChainSync; use ethcore::service::SyncMessage; use io::NetSyncIo; @@ -71,6 +72,23 @@ mod range_collection; #[cfg(test)] mod tests; +/// Sync configuration +pub struct SyncConfig { + /// Max blocks to download ahead + pub max_download_ahead_blocks: usize, + /// Network ID + pub network_id: U256, +} + +impl Default for SyncConfig { + fn default() -> SyncConfig { + SyncConfig { + max_download_ahead_blocks: 20000, + network_id: ONE_U256, + } + } +} + /// Ethereum network protocol handler pub struct EthSync { /// Shared blockchain client. TODO: this should evetually become an IPC endpoint @@ -83,10 +101,10 @@ pub use self::chain::{SyncStatus, SyncState}; impl EthSync { /// Creates and register protocol with the network service - pub fn register(service: &mut NetworkService, chain: Arc) -> Arc { + pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc) -> Arc { let sync = Arc::new(EthSync { chain: chain, - sync: RwLock::new(ChainSync::new()), + sync: RwLock::new(ChainSync::new(config)), }); service.register_protocol(sync.clone(), "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler"); sync diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index c3333ab63..0a1bb6c6f 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -207,7 +207,7 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } #[test] -#[allow(cyclomatic_complexity)] +#[cfg_attr(dev, allow(cyclomatic_complexity))] fn test_range() { use std::cmp::{Ordering}; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 8c8b3b10a..6e92184c8 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -20,7 +20,8 @@ use ethcore::block_queue::BlockQueueInfo; use ethcore::header::{Header as BlockHeader, BlockNumber}; use ethcore::error::*; use io::SyncIo; -use chain::{ChainSync}; +use chain::ChainSync; +use ::SyncConfig; use ethcore::receipt::Receipt; use ethcore::transaction::LocalizedTransaction; @@ -330,7 +331,7 @@ impl TestNet { for _ in 0..n { net.peers.push(TestPeer { chain: TestBlockChainClient::new(), - sync: ChainSync::new(), + sync: ChainSync::new(SyncConfig::default()), queue: VecDeque::new(), }); } From 1a73d703342ee3b62f807637aa6e0fa58a729f7d Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 24 Feb 2016 22:37:28 +0100 Subject: [PATCH 201/753] Report memory usage --- sync/Cargo.toml | 1 + sync/src/chain.rs | 14 +++++++++++++- sync/src/lib.rs | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 7a81c7d97..26a7d463c 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -15,6 +15,7 @@ log = "0.3" env_logger = "0.3" time = "0.1.34" rand = "0.3.13" +heapsize = "0.3" [features] default = [] diff --git a/sync/src/chain.rs b/sync/src/chain.rs index bea17c177..01446adaf 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -39,9 +39,10 @@ use ethcore::error::*; use ethcore::block::Block; use io::SyncIo; use time; -use std::option::Option; use super::SyncConfig; +known_heap_size!(0, PeerInfo, Header, HeaderId); + impl ToUsize for BlockNumber { fn to_usize(&self) -> usize { *self as usize @@ -134,6 +135,8 @@ pub struct SyncStatus { pub num_peers: usize, /// Total number of active peers pub num_active_peers: usize, + /// Heap memory used in bytes + pub mem_used: usize, } #[derive(PartialEq, Eq, Debug, Clone)] @@ -246,6 +249,15 @@ impl ChainSync { blocks_total: match self.highest_block { None => 0, Some(x) => x - self.starting_block }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), + mem_used: + // TODO: https://github.com/servo/heapsize/pull/50 + // self.downloading_hashes.heap_size_of_children() + //+ self.downloading_bodies.heap_size_of_children() + //+ self.downloading_hashes.heap_size_of_children() + self.headers.heap_size_of_children() + + self.bodies.heap_size_of_children() + + self.peers.heap_size_of_children() + + self.header_ids.heap_size_of_children(), } } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 397a09f47..9bf715f07 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -54,6 +54,8 @@ extern crate ethcore; extern crate env_logger; extern crate time; extern crate rand; +#[macro_use] +extern crate heapsize; use std::ops::*; use std::sync::*; From ccaa1946810e5566304f5e6e5cc2f33883f2a99b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 02:00:34 +0300 Subject: [PATCH 202/753] mul, bench showtime --- util/benches/bigint.rs | 20 ++++- util/src/uint.rs | 161 +++++++++++++++++++++++++++++++++-------- 2 files changed, 150 insertions(+), 31 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 524d31508..38ce10a4a 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -21,6 +21,7 @@ //! ``` #![feature(test)] +#![feature(asm)] extern crate test; extern crate ethcore_util; @@ -40,7 +41,24 @@ fn u256_add(b: &mut Bencher) { fn u256_sub(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256::zero(), |old, new| { old.overflowing_add(U256::from(new)).0 }) + (0..n).fold(U256::zero(), |old, new| { old.overflowing_sub(U256::from(new)).0 }) + }); +} + +#[bench] +fn u256_mul(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256([12345u64, 0u64, 0u64, 0u64]), |old, new| { old.overflowing_mul(U256::from(new)).0 }) + }); +} + + +#[bench] +fn u128_mul(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U128([12345u64, 0u64]), |old, new| { old.overflowing_mul(U128::from(new)).0 }) }); } diff --git a/util/src/uint.rs b/util/src/uint.rs index 147b83e42..38b4e4906 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -41,8 +41,6 @@ use from_json::*; use rustc_serialize::hex::ToHex; use serde; -#[cfg_attr(x64_asm_optimizations, all(feature = "dev", target_arch = "x86_64"))] - macro_rules! impl_map_from { ($thing:ident, $from:ty, $to:ty) => { impl From<$from> for $thing { @@ -53,7 +51,8 @@ macro_rules! impl_map_from { } } -macro_rules! overflowing_add_regular { +#[cfg(not(all(feature="dev", target_arch = "x86_64")))] +macro_rules! uint_overflowing_add { ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ let $name(ref me) = $self_expr; let $name(ref you) = $other; @@ -83,7 +82,8 @@ macro_rules! overflowing_add_regular { }) } -macro_rules! add_64x_optimized { +#[cfg(all(feature="dev", target_arch = "x86_64"))] +macro_rules! uint_overflowing_add { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; @@ -110,7 +110,17 @@ macro_rules! add_64x_optimized { ) } -macro_rules! sub_64x_optimized { +#[cfg(not(all(feature="dev", target_arch = "x86_64")))] +macro_rules! uint_overflowing_sub { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let res = overflowing!((!$other).overflowing_add(From::from(1u64))); + let res = overflowing!($self_expr.overflowing_add(res)); + (res, $self_expr < $other) + }) +} + +#[cfg(all(feature="dev", target_arch = "x86_64"))] +macro_rules! uint_overflowing_sub { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; @@ -137,6 +147,119 @@ macro_rules! sub_64x_optimized { ) } +#[cfg(all(feature="dev", target_arch = "x86_64"))] +macro_rules! uint_overflowing_mul { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 4] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + unsafe { + asm!(" + mov $5, %rax + mulq $9 + mov %rax, %r8 + adc $6, %rdx + pushf + + mov %rdx, %rax + mulq $9 + popf + adc $$0, %rax + adc $7, %rdx + pushf + mov %rax, %r9 + + + mov %rdx, %rax + mulq $9 + popf + adc $$0, %rax + adc $8, %rdx + pushf + mov %rax, %r10 + + mov %rdx, %rax + mulq $9 + popf + adc $$0, %rax + mov %rax, %r11 + mov %rdx, %rcx + + mov $5, %rax + mulq $10 + adc %rax, %r9 + adc $6, %rdx + pushf + + mov %rdx, %rax + mulq $10 + popf + adc %rax, %r10 + adc $7, %rdx + pushf + + mov %rdx, %rax + mulq $10 + popf + adc %rax, %r11 + pushf + or %rax, %rcx + + mov $5, %rax + mulq $11 + popf + adc %rax, %r10 + adc $6, %rdx + pushf + + mov %rdx, %rax + mulq $11 + popf + adc %rax, %r11 + pushf + or %rdx, %rcx + + mov $5, %rax + mulq $12 + popf + adc %rax, %r11 + or %rdx, %rcx + " + : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), + /* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow) + + : /* $5 */ "m"(self_t[0]), /* $6 */ "m"(self_t[1]), /* $7 */ "m"(self_t[2]), + /* $8 */ "m"(self_t[3]), /* $9 */ "m"(other_t[0]), /* $10 */ "m"(other_t[1]), + /* $11 */ "m"(other_t[2]), /* $12 */ "m"(other_t[3]) + : "rax", "rdx" + : + + ); + } + (U256(result), overflow > 0) + }); + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( + overflowing_mul_regular!($name, $n_words, $self_expr, $other) + ) +} + +#[cfg(not(all(feature="dev", target_arch = "x86_64")))] +macro_rules! uint_overflowing_mul { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut res = $name::from(0u64); + let mut overflow = false; + // TODO: be more efficient about this + for i in 0..(2 * $n_words) { + let v = overflowing!($self_expr.overflowing_mul_u32(($other >> (32 * i)).low_u32()), overflow); + let res2 = overflowing!(v.overflowing_shl(32 * i as u32), overflow); + res = overflowing!(res.overflowing_add(res2), overflow); + } + (res, overflow) + }) +} + macro_rules! overflowing { ($op: expr, $overflow: expr) => ( { @@ -384,38 +507,16 @@ macro_rules! construct_uint { } /// Optimized instructions - #[cfg(x64_asm_optimizations)] - #[inline] fn overflowing_add(self, other: $name) -> ($name, bool) { - add_64x_optimized!($name, $n_words, self, other) - } - #[cfg(not(x64_asm_optimizations))] - fn overflowing_add(self, other: $name) -> ($name, bool) { - overflowing_add_regular!($name, $n_words, self, other) + uint_overflowing_add!($name, $n_words, self, other) } - #[cfg(x64_asm_optimizations)] - #[inline] fn overflowing_sub(self, other: $name) -> ($name, bool) { - sub_64x_optimized!($name, $n_words, self, other) - } - #[cfg(not(x64_asm_optimizations))] - fn overflowing_sub(self, other: $name) -> ($name, bool) { - let res = overflowing!((!other).overflowing_add(From::from(1u64))); - let res = overflowing!(self.overflowing_add(res)); - (res, self < other) + uint_overflowing_sub!($name, $n_words, self, other) } fn overflowing_mul(self, other: $name) -> ($name, bool) { - let mut res = $name::from(0u64); - let mut overflow = false; - // TODO: be more efficient about this - for i in 0..(2 * $n_words) { - let v = overflowing!(self.overflowing_mul_u32((other >> (32 * i)).low_u32()), overflow); - let res2 = overflowing!(v.overflowing_shl(32 * i as u32), overflow); - res = overflowing!(res.overflowing_add(res2), overflow); - } - (res, overflow) + uint_overflowing_mul!($name, $n_words, self, other) } fn overflowing_div(self, other: $name) -> ($name, bool) { From 0794049d18708a3d258df42cd43f51ce03a9ae33 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 02:05:59 +0300 Subject: [PATCH 203/753] fix naughty macros --- util/src/uint.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 38b4e4906..f27150199 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -53,6 +53,12 @@ macro_rules! impl_map_from { #[cfg(not(all(feature="dev", target_arch = "x86_64")))] macro_rules! uint_overflowing_add { + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_add_reg { ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ let $name(ref me) = $self_expr; let $name(ref you) = $other; @@ -82,6 +88,7 @@ macro_rules! uint_overflowing_add { }) } + #[cfg(all(feature="dev", target_arch = "x86_64"))] macro_rules! uint_overflowing_add { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ @@ -106,7 +113,7 @@ macro_rules! uint_overflowing_add { (U256(result), overflow != 0) }); ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( - overflowing_add_regular!($name, $n_words, $self_expr, $other) + uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) ) } @@ -142,9 +149,11 @@ macro_rules! uint_overflowing_sub { } (U256(result), overflow != 0) }); - ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( - overflowing_add_regular!($name, $n_words, $self_expr, $other) - ) + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let res = overflowing!((!$other).overflowing_add(From::from(1u64))); + let res = overflowing!($self_expr.overflowing_add(res)); + (res, $self_expr < $other) + }) } #[cfg(all(feature="dev", target_arch = "x86_64"))] @@ -241,12 +250,18 @@ macro_rules! uint_overflowing_mul { (U256(result), overflow > 0) }); ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( - overflowing_mul_regular!($name, $n_words, $self_expr, $other) + uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) ) } #[cfg(not(all(feature="dev", target_arch = "x86_64")))] macro_rules! uint_overflowing_mul { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_mul_reg { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut res = $name::from(0u64); let mut overflow = false; From da69ea51fe2c5da3b540fb07066588a7a4e27d1e Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 03:09:33 +0300 Subject: [PATCH 204/753] inline --- util/benches/bigint.rs | 12 ++++++++++-- util/src/uint.rs | 27 ++++++++++++++++----------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 38ce10a4a..3a9c6d118 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -33,7 +33,15 @@ use ethcore_util::uint::*; fn u256_add(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256::zero(), |old, new| { old.overflowing_add(U256::from(new)).0 }) + (0..n).fold(U256::from(1234599u64), |old, new| { old.overflowing_add(U256::from(new)).0 }) + }); +} + +#[bench] +fn u256_uber_add(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256::from(1234599u64), |old, new| { old.uber_add(U256::from(new)).0 }) }); } @@ -41,7 +49,7 @@ fn u256_add(b: &mut Bencher) { fn u256_sub(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256::zero(), |old, new| { old.overflowing_sub(U256::from(new)).0 }) + (0..n).fold(U256::from(::std::u64::MAX), |old, new| { old.overflowing_sub(U256::from(new)).0 }) }); } diff --git a/util/src/uint.rs b/util/src/uint.rs index f27150199..8dd7d8638 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -97,17 +97,19 @@ macro_rules! uint_overflowing_add { let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; let overflow: u8; - unsafe { - asm!(" - adc $9, $0 - adc $10, $1 - adc $11, $2 - adc $12, $3 - setc %al" - : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) - : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) - : - : + unsafe { + asm!(" + adc $9, %r8 + adc $10, %r9 + adc $11, %r10 + adc $12, %r11 + setc %al + " + : "={r8}"(result[0]), "={r9}"(result[1]), "={r10}"(result[2]), "={r11}"(result[3]), "={al}"(overflow) + : "{r8}"(self_t[0]), "{r9}"(self_t[1]), "{r10}"(self_t[2]), "{r11}"(self_t[3]), + "m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]) + : + : ); } (U256(result), overflow != 0) @@ -522,14 +524,17 @@ macro_rules! construct_uint { } /// Optimized instructions + #[inline(always)] fn overflowing_add(self, other: $name) -> ($name, bool) { uint_overflowing_add!($name, $n_words, self, other) } + #[inline(always)] fn overflowing_sub(self, other: $name) -> ($name, bool) { uint_overflowing_sub!($name, $n_words, self, other) } + #[inline(always)] fn overflowing_mul(self, other: $name) -> ($name, bool) { uint_overflowing_mul!($name, $n_words, self, other) } From ae76a509dcc956ea329781bbc9cb6b6cc373580e Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 03:10:02 +0300 Subject: [PATCH 205/753] inline test --- util/benches/bigint.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 3a9c6d118..826d5023e 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -37,13 +37,6 @@ fn u256_add(b: &mut Bencher) { }); } -#[bench] -fn u256_uber_add(b: &mut Bencher) { - b.iter(|| { - let n = black_box(10000); - (0..n).fold(U256::from(1234599u64), |old, new| { old.uber_add(U256::from(new)).0 }) - }); -} #[bench] fn u256_sub(b: &mut Bencher) { From 781f763f1f50463117959f9e2d1bf0be83f1a081 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Feb 2016 14:09:39 +0100 Subject: [PATCH 206/753] Memory management --- Cargo.lock | 10 ++++++ Cargo.toml | 1 + ethcore/src/block_queue.rs | 65 ++++++++++++++++++++++++++++++----- ethcore/src/blockchain.rs | 66 +++++++++++++++++------------------- ethcore/src/client.rs | 28 ++++++++++----- ethcore/src/lib.rs | 6 ++-- ethcore/src/service.rs | 9 ++--- ethcore/src/tests/client.rs | 12 +++---- ethcore/src/tests/helpers.rs | 14 ++++---- parity/main.rs | 35 +++++++++++++------ sync/src/tests/helpers.rs | 4 ++- 11 files changed, 167 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1ef76816..695b060f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,7 @@ dependencies = [ "ethsync 0.9.99", "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -255,6 +256,7 @@ dependencies = [ "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", + "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -526,6 +528,14 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "number_prefix" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "odds" version = "0.2.12" diff --git a/Cargo.toml b/Cargo.toml index 2de097ad9..9b8ec6405 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } daemonize = "0.2" ethcore-devtools = { path = "devtools" } +number_prefix = "0.2" [features] default = ["rpc"] diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index c39f158f0..0f5985f06 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -28,6 +28,28 @@ use service::*; use client::BlockStatus; use util::panics::*; +known_heap_size!(0, UnVerifiedBlock, VerifyingBlock, PreVerifiedBlock); + +/// Block queue configuration +#[derive(Debug)] +pub struct BlockQueueConfig { + /// Maximum number of blocks to keep in unverified queue. + /// When the limit is reached, is_full returns true. + pub max_queue_size: usize, + /// Maximum heap memory to use. + /// When the limit is reached, is_full returns true. + pub max_mem_use: usize, +} + +impl Default for BlockQueueConfig { + fn default() -> Self { + BlockQueueConfig { + max_queue_size: 30000, + max_mem_use: 50 * 1024 * 1024, + } + } +} + /// Block queue status #[derive(Debug)] pub struct BlockQueueInfo { @@ -37,6 +59,12 @@ pub struct BlockQueueInfo { pub verified_queue_size: usize, /// Number of blocks being verified pub verifying_queue_size: usize, + /// Configured maximum number of blocks in the queue + pub max_queue_size: usize, + /// Configured maximum number of bytes to use + pub max_mem_use: usize, + /// Heap memory used in bytes + pub mem_used: usize, } impl BlockQueueInfo { @@ -48,7 +76,8 @@ impl BlockQueueInfo { /// Indicates that queue is full pub fn is_full(&self) -> bool { - self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size > MAX_UNVERIFIED_QUEUE_SIZE + self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size > self.max_queue_size || + self.mem_used > self.max_mem_use } /// Indicates that queue is empty @@ -68,7 +97,9 @@ pub struct BlockQueue { deleting: Arc, ready_signal: Arc, empty: Arc, - processing: RwLock> + processing: RwLock>, + max_queue_size: usize, + max_mem_use: usize, } struct UnVerifiedBlock { @@ -106,11 +137,9 @@ struct Verification { bad: HashSet, } -const MAX_UNVERIFIED_QUEUE_SIZE: usize = 50000; - impl BlockQueue { /// Creates a new queue instance. - pub fn new(engine: Arc>, message_channel: IoChannel) -> BlockQueue { + pub fn new(config: BlockQueueConfig, engine: Arc>, message_channel: IoChannel) -> BlockQueue { let verification = Arc::new(Mutex::new(Verification::default())); let more_to_verify = Arc::new(Condvar::new()); let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel }); @@ -133,7 +162,7 @@ impl BlockQueue { .name(format!("Verifier #{}", i)) .spawn(move || { panic_handler.catch_panic(move || { - BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) + BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) }).unwrap() }) .expect("Error starting block verification thread") @@ -149,6 +178,8 @@ impl BlockQueue { deleting: deleting.clone(), processing: RwLock::new(HashSet::new()), empty: empty.clone(), + max_queue_size: config.max_queue_size, + max_mem_use: config.max_mem_use, } } @@ -334,8 +365,26 @@ impl BlockQueue { verified_queue_size: verification.verified.len(), unverified_queue_size: verification.unverified.len(), verifying_queue_size: verification.verifying.len(), + max_queue_size: self.max_queue_size, + max_mem_use: self.max_mem_use, + mem_used: + verification.unverified.heap_size_of_children() + + verification.verifying.heap_size_of_children() + + verification.verified.heap_size_of_children(), + // TODO: https://github.com/servo/heapsize/pull/50 + //+ self.processing.read().unwrap().heap_size_of_children(), } } + + pub fn collect_garbage(&self) { + { + let mut verification = self.verification.lock().unwrap(); + verification.unverified.shrink_to_fit(); + verification.verifying.shrink_to_fit(); + verification.verified.shrink_to_fit(); + } + self.processing.write().unwrap().shrink_to_fit(); + } } impl MayPanic for BlockQueue { @@ -367,7 +416,7 @@ mod tests { fn get_test_queue() -> BlockQueue { let spec = get_test_spec(); let engine = spec.to_engine().unwrap(); - BlockQueue::new(Arc::new(engine), IoChannel::disconnected()) + BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected()) } #[test] @@ -375,7 +424,7 @@ mod tests { // TODO better test let spec = Spec::new_test(); let engine = spec.to_engine().unwrap(); - let _ = BlockQueue::new(Arc::new(engine), IoChannel::disconnected()); + let _ = BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected()); } #[test] diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index cc9ff56fd..6907369f4 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -23,6 +23,24 @@ use extras::*; use transaction::*; use views::*; +/// Blockchain configuration. +#[derive(Debug)] +pub struct BlockChainConfig { + /// Preferred cache size in bytes. + pub pref_cache_size: usize, + /// Maximum cache size in bytes. + pub max_cache_size: usize, +} + +impl Default for BlockChainConfig { + fn default() -> Self { + BlockChainConfig { + pref_cache_size: 1 << 14, + max_cache_size: 1 << 20, + } + } +} + /// Represents a tree route between `from` block and `to` block: pub struct TreeRoute { /// A vector of hashes of all blocks, ordered from `from` to `to`. @@ -50,7 +68,7 @@ pub struct CacheSize { impl CacheSize { /// Total amount used by the cache. - fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms } + pub fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms } } /// Information about best block gathered together @@ -220,33 +238,7 @@ const COLLECTION_QUEUE_SIZE: usize = 8; impl BlockChain { /// Create new instance of blockchain from given Genesis - /// - /// ```rust - /// extern crate ethcore_util as util; - /// extern crate ethcore; - /// use std::env; - /// use std::str::FromStr; - /// use ethcore::spec::*; - /// use ethcore::blockchain::*; - /// use ethcore::ethereum; - /// use util::hash::*; - /// use util::uint::*; - /// - /// fn main() { - /// let spec = ethereum::new_frontier(); - /// - /// let mut dir = env::temp_dir(); - /// dir.push(H32::random().hex()); - /// - /// let bc = BlockChain::new(&spec.genesis_block(), &dir); - /// - /// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"; - /// assert_eq!(bc.genesis_hash(), H256::from_str(genesis_hash).unwrap()); - /// assert!(bc.is_known(&bc.genesis_hash())); - /// assert_eq!(bc.genesis_hash(), bc.block_hash(0).unwrap()); - /// } - /// ``` - pub fn new(genesis: &[u8], path: &Path) -> BlockChain { + pub fn new(config: BlockChainConfig, genesis: &[u8], path: &Path) -> BlockChain { // open extras db let mut extras_path = path.to_path_buf(); extras_path.push("extras"); @@ -261,8 +253,8 @@ impl BlockChain { (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new())); let bc = BlockChain { - pref_cache_size: 1 << 14, - max_cache_size: 1 << 20, + pref_cache_size: config.pref_cache_size, + max_cache_size: config.max_cache_size, best_block: RwLock::new(BestBlock::new()), blocks: RwLock::new(HashMap::new()), block_details: RwLock::new(HashMap::new()), @@ -536,6 +528,8 @@ impl BlockChain { } /// Returns true if transaction is known. + // TODO: Use me + #[allow(dead_code)] pub fn is_known_transaction(&self, hash: &H256) -> bool { self.query_extras_exist(hash, &self.transaction_addresses) } @@ -556,6 +550,8 @@ impl BlockChain { } /// Get the transactions' log blooms of a block. + // TODO: Use me + #[allow(dead_code)] pub fn log_blooms(&self, hash: &H256) -> Option { self.query_extras(hash, &self.block_logs) } @@ -671,7 +667,7 @@ mod tests { let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap(); let temp = RandomTempPath::new(); - let bc = BlockChain::new(&genesis, temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap(); @@ -715,7 +711,7 @@ mod tests { let best_block_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap(); let temp = RandomTempPath::new(); - let bc = BlockChain::new(&genesis, temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); bc.insert_block(&b1); bc.insert_block(&b2); bc.insert_block(&b3a); @@ -794,14 +790,14 @@ mod tests { let temp = RandomTempPath::new(); { - let bc = BlockChain::new(&genesis, temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); assert_eq!(bc.best_block_hash(), genesis_hash); bc.insert_block(&b1); assert_eq!(bc.best_block_hash(), b1_hash); } { - let bc = BlockChain::new(&genesis, temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); assert_eq!(bc.best_block_hash(), b1_hash); } } @@ -854,7 +850,7 @@ mod tests { let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap(); let temp = RandomTempPath::new(); - let bc = BlockChain::new(&genesis, temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); bc.insert_block(&b1); let transactions = bc.transactions(&b1_hash).unwrap(); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c3ec4b4d0..333917e4a 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -19,7 +19,7 @@ use util::*; use util::panics::*; use rocksdb::{Options, DB, DBCompactionStyle}; -use blockchain::{BlockChain, BlockProvider, CacheSize}; +use blockchain::{BlockChain, BlockProvider}; use views::BlockView; use error::*; use header::BlockNumber; @@ -27,14 +27,16 @@ use state::State; use spec::Spec; use engine::Engine; use views::HeaderView; -use block_queue::{BlockQueue, BlockQueueInfo}; +use block_queue::BlockQueue; use service::{NetSyncMessage, SyncMessage}; use env_info::LastHashes; use verification::*; use block::*; use transaction::LocalizedTransaction; use extras::TransactionAddress; -pub use blockchain::TreeRoute; +pub use block_queue::{BlockQueueConfig, BlockQueueInfo}; +pub use blockchain::{TreeRoute, BlockChainConfig, CacheSize as BlockChainCacheSize}; + /// Uniquely identifies block. #[derive(Debug, PartialEq, Clone)] @@ -73,7 +75,16 @@ pub enum BlockStatus { Unknown, } -/// Information about the blockchain gthered together. +/// Client configuration. Includes configs for all sub-systems. +#[derive(Debug, Default)] +pub struct ClientConfig { + /// Block queue configuration. + pub queue: BlockQueueConfig, + /// Blockchain configuration. + pub blockchain: BlockChainConfig, +} + +/// Information about the blockchain gathered together. #[derive(Debug)] pub struct BlockChainInfo { /// Blockchain difficulty. @@ -183,14 +194,14 @@ const CLIENT_DB_VER_STR: &'static str = "2.1"; impl Client { /// Create a new client with given spec and DB path. - pub fn new(spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { + pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { let mut dir = path.to_path_buf(); dir.push(H64::from(spec.genesis_header().hash()).hex()); //TODO: sec/fat: pruned/full versioning dir.push(format!("v{}-sec-pruned", CLIENT_DB_VER_STR)); let path = dir.as_path(); let gb = spec.genesis_block(); - let chain = Arc::new(RwLock::new(BlockChain::new(&gb, path))); + let chain = Arc::new(RwLock::new(BlockChain::new(config.blockchain, &gb, path))); let mut opts = Options::new(); opts.set_max_open_files(256); opts.create_if_missing(true); @@ -223,7 +234,7 @@ impl Client { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); } - let block_queue = BlockQueue::new(engine.clone(), message_channel); + let block_queue = BlockQueue::new(config.queue, engine.clone(), message_channel); let panic_handler = PanicHandler::new_in_arc(); panic_handler.forward_from(&block_queue); @@ -330,7 +341,7 @@ impl Client { } /// Get info on the cache. - pub fn cache_info(&self) -> CacheSize { + pub fn blockchain_cache_info(&self) -> BlockChainCacheSize { self.chain.read().unwrap().cache_size() } @@ -342,6 +353,7 @@ impl Client { /// Tick the client. pub fn tick(&self) { self.chain.read().unwrap().collect_garbage(); + self.block_queue.read().unwrap().collect_garbage(); } /// Set up the cache behaviour. diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 3d43fd725..17bd52159 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -85,7 +85,7 @@ #[macro_use] extern crate lazy_static; extern crate rustc_serialize; extern crate rocksdb; -extern crate heapsize; +#[macro_use] extern crate heapsize; extern crate crypto; extern crate time; extern crate env_logger; @@ -96,8 +96,6 @@ extern crate crossbeam; #[cfg(feature = "jit" )] extern crate evmjit; pub mod block; -pub mod blockchain; -pub mod block_queue; pub mod client; pub mod error; pub mod ethereum; @@ -129,6 +127,8 @@ mod substate; mod executive; mod externalities; mod verification; +mod block_queue; +mod blockchain; #[cfg(test)] mod tests; diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 534aab49d..ea80e7c80 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -20,7 +20,7 @@ use util::*; use util::panics::*; use spec::Spec; use error::*; -use client::Client; +use client::{Client, ClientConfig}; /// Message type for external and internal events #[derive(Clone)] @@ -43,14 +43,14 @@ pub struct ClientService { impl ClientService { /// Start the service in a separate thread. - pub fn start(spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result { + pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result { let panic_handler = PanicHandler::new_in_arc(); let mut net_service = try!(NetworkService::start(net_config)); panic_handler.forward_from(&net_service); info!("Starting {}", net_service.host_info()); info!("Configured for {} using {} engine", spec.name, spec.engine_name); - let client = try!(Client::new(spec, db_path, net_service.io().channel())); + let client = try!(Client::new(config, spec, db_path, net_service.io().channel())); panic_handler.forward_from(client.deref()); let client_io = Arc::new(ClientIoHandler { client: client.clone() @@ -130,12 +130,13 @@ mod tests { use tests::helpers::*; use util::network::*; use devtools::*; + use client::ClientConfig; #[test] fn it_can_be_started() { let spec = get_test_spec(); let temp_path = RandomTempPath::new(); - let service = ClientService::start(spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path()); + let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path()); assert!(service.is_ok()); } } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index af25d1b72..83df81fa2 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use client::{BlockChainClient, Client, BlockId}; +use client::{BlockChainClient, Client, ClientConfig, BlockId}; use tests::helpers::*; use common::*; use devtools::*; @@ -22,14 +22,14 @@ use devtools::*; #[test] fn created() { let dir = RandomTempPath::new(); - let client_result = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()); + let client_result = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()); assert!(client_result.is_ok()); } #[test] fn imports_from_empty() { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); client.import_verified_blocks(&IoChannel::disconnected()); client.flush_queue(); } @@ -37,7 +37,7 @@ fn imports_from_empty() { #[test] fn imports_good_block() { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let good_block = get_good_dummy_block(); if let Err(_) = client.import_block(good_block) { panic!("error importing block being good by definition"); @@ -52,7 +52,7 @@ fn imports_good_block() { #[test] fn query_none_block() { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let non_existant = client.block_header(BlockId::Number(188)); assert!(non_existant.is_none()); @@ -104,5 +104,5 @@ fn can_collect_garbage() { let client_result = generate_dummy_client(100); let client = client_result.reference(); client.tick(); - assert!(client.cache_info().blocks < 100 * 1024); + assert!(client.blockchain_cache_info().blocks < 100 * 1024); } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 56653e820..510833f4d 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use client::{BlockChainClient, Client}; +use client::{BlockChainClient, Client, ClientConfig}; use common::*; use spec::*; -use blockchain::{BlockChain}; +use blockchain::{BlockChain, BlockChainConfig}; use state::*; use rocksdb::*; use evm::{Schedule, Factory}; @@ -135,7 +135,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let test_spec = get_test_spec(); let test_engine = test_spec.to_engine().unwrap(); let state_root = test_engine.spec().genesis_header().state_root; @@ -173,7 +173,7 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); for block in &blocks { if let Err(_) = client.import_block(block.clone()) { panic!("panic importing block which is well-formed"); @@ -190,7 +190,7 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult GuardedTempResult { let temp = RandomTempPath::new(); - let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path()); for block_order in 1..block_number { bc.insert_block(&create_unverifiable_block(block_order, bc.best_block_hash())); } @@ -203,7 +203,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult GuardedTempResult { let temp = RandomTempPath::new(); - let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path()); for block_order in 1..block_number { bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None)); } @@ -216,7 +216,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { let temp = RandomTempPath::new(); - let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path()); GuardedTempResult:: { _temp: temp, diff --git a/parity/main.rs b/parity/main.rs index e95f38f13..fad2be840 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -31,6 +31,7 @@ extern crate ctrlc; extern crate fdlimit; extern crate daemonize; extern crate time; +extern crate number_prefix; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -47,10 +48,10 @@ use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; -use ethcore::blockchain::CacheSize; use ethsync::{EthSync, SyncConfig}; use docopt::Docopt; use daemonize::Daemonize; +use number_prefix::{binary_prefix, Standalone, Prefixed}; const USAGE: &'static str = " Parity. Ethereum Client. @@ -78,6 +79,7 @@ Options: --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. + --queue-max-size BYTES Specify the maximum size of memory to use for block queue [default: 52428800]. -j --jsonrpc Enable the JSON-RPC API sever. --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. @@ -105,6 +107,7 @@ struct Args { flag_node_key: Option, flag_cache_pref_size: usize, flag_cache_max_size: usize, + flag_queue_max_size: usize, flag_jsonrpc: bool, flag_jsonrpc_url: String, flag_logging: Option, @@ -285,9 +288,12 @@ impl Configuration { sync_config.network_id = spec.network_id(); // Build client - let mut service = ClientService::start(spec, net_settings, &Path::new(&self.path())).unwrap(); + let mut client_config = ClientConfig::default(); + client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; + client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; + client_config.queue.max_mem_use = self.args.flag_queue_max_size; + let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let client = service.client().clone(); - client.configure_cache(self.args.flag_cache_pref_size, self.args.flag_cache_max_size); // Sync let sync = EthSync::register(service.network(), sync_config, client); @@ -331,7 +337,7 @@ fn main() { struct Informant { chain_info: RwLock>, - cache_info: RwLock>, + cache_info: RwLock>, report: RwLock>, } @@ -346,18 +352,26 @@ impl Default for Informant { } impl Informant { + + fn format_bytes(b: usize) -> String { + match binary_prefix(b as f64) { + Standalone(bytes) => format!("{} bytes", bytes), + Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix), + } + } + pub fn tick(&self, client: &Client, sync: &EthSync) { // 5 seconds betwen calls. TODO: calculate this properly. let dur = 5usize; let chain_info = client.chain_info(); let queue_info = client.queue_info(); - let cache_info = client.cache_info(); + let cache_info = client.blockchain_cache_info(); let report = client.report(); let sync_info = sync.status(); - if let (_, &Some(ref last_cache_info), &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { - println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// {} ({}) bl {} ({}) ex ]", + if let (_, _, &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { + println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} chain, {} queue, {} sync ]", chain_info.best_block_number, chain_info.best_block_hash, (report.blocks_imported - last_report.blocks_imported) / dur, @@ -370,10 +384,9 @@ impl Informant { queue_info.unverified_queue_size, queue_info.verified_queue_size, - cache_info.blocks, - cache_info.blocks as isize - last_cache_info.blocks as isize, - cache_info.block_details, - cache_info.block_details as isize - last_cache_info.block_details as isize + Informant::format_bytes(cache_info.total()), + Informant::format_bytes(queue_info.mem_used), + Informant::format_bytes(sync_info.mem_used), ); } diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 6e92184c8..05b190573 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -16,7 +16,7 @@ use util::*; use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId}; -use ethcore::block_queue::BlockQueueInfo; +use ethcore::BlockQueueInfo; use ethcore::header::{Header as BlockHeader, BlockNumber}; use ethcore::error::*; use io::SyncIo; @@ -242,6 +242,8 @@ impl BlockChainClient for TestBlockChainClient { verified_queue_size: 0, unverified_queue_size: 0, verifying_queue_size: 0, + max_unverified: 0, + mem_used: 0, } } From f17d893f53f2551d51e590cb4ce2d296750f4093 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 16:20:57 +0300 Subject: [PATCH 207/753] fixed mul, fixed register pref --- util/src/uint.rs | 159 +++++++++++++++++++++++++++-------------------- 1 file changed, 93 insertions(+), 66 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 8dd7d8638..6869c3ec1 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -99,15 +99,15 @@ macro_rules! uint_overflowing_add { let overflow: u8; unsafe { asm!(" - adc $9, %r8 - adc $10, %r9 - adc $11, %r10 - adc $12, %r11 + adc $9, $0 + adc $10, $1 + adc $11, $2 + adc $12, $3 setc %al " - : "={r8}"(result[0]), "={r9}"(result[1]), "={r10}"(result[2]), "={r11}"(result[3]), "={al}"(overflow) - : "{r8}"(self_t[0]), "{r9}"(self_t[1]), "{r10}"(self_t[2]), "{r11}"(self_t[3]), - "m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]) + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) : : ); @@ -138,10 +138,10 @@ macro_rules! uint_overflowing_sub { let overflow: u8; unsafe { asm!(" - sbb $9, %r8 - sbb $10, %r9 - sbb $11, %r10 - sbb $12, %r11 + sbb $9, $0 + sbb $10, $1 + sbb $11, $2 + sbb $12, $3 setb %al" : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) @@ -168,76 +168,103 @@ macro_rules! uint_overflowing_mul { let overflow: u8; unsafe { asm!(" + clc mov $5, %rax mulq $9 - mov %rax, %r8 - adc $6, %rdx - pushf + mov %rax, $0 + mov %rdx, $1 - mov %rdx, %rax + mov $6, %rax + mulq $9 + clc + adc %rax, $1 + mov %rdx, $2 + + mov $5, %rax + pushf + mulq $10 + popf + adc %rax, $1 + adc %rdx, $2 + + mov $6, %rax + mulq $10 + clc + adc %rax, $2 + mov %rdx, $3 + + mov $7, %rax + mulq $9 + clc + adc %rax, $2 + adc %rdx, $3 + + mov $5, %rax + mulq $11 + clc + adc %rax, $2 + adc %rdx, $3 + + mov $8, %rax + pushf mulq $9 popf - adc $$0, %rax - adc $7, %rdx - pushf - mov %rax, %r9 - - - mov %rdx, %rax - mulq $9 - popf - adc $$0, %rax - adc $8, %rdx - pushf - mov %rax, %r10 - - mov %rdx, %rax - mulq $9 - popf - adc $$0, %rax - mov %rax, %r11 + adc %rax, $3 + adc $$0, %rdx mov %rdx, %rcx + clc - mov $5, %rax - mulq $10 - adc %rax, %r9 - adc $6, %rdx + mov $7, %rax pushf - - mov %rdx, %rax mulq $10 popf - adc %rax, %r10 - adc $7, %rdx - pushf - - mov %rdx, %rax - mulq $10 - popf - adc %rax, %r11 - pushf - or %rax, %rcx - - mov $5, %rax - mulq $11 - popf - adc %rax, %r10 - adc $6, %rdx - pushf - - mov %rdx, %rax - mulq $11 - popf - adc %rax, %r11 - pushf + adc %rax, $3 + adc $$0, %rdx or %rdx, %rcx + clc + + mov $6, %rax + pushf + mulq $11 + popf + adc %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + clc mov $5, %rax + pushf mulq $12 popf - adc %rax, %r11 - or %rdx, %rcx - " + adc %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + clc + + cmpq $$0, %rcx + jne 2f + + mov $8, %rax + cmpq $$0, %rax + setz %cl + + mov $7, %rax + cmpq $$0, %rax + sete %dl + or %dl, %cl + + mov $3, %rax + cmpq $$0, %rax + sete %dl + + mov $2, %rax + cmpq $$0, %rax + sete %bl + or %bl, %dl + + and %dl, %cl + + 2: " : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), /* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow) From 85350f3c66f0c41f2483840baf4fc36fb19e8992 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 25 Feb 2016 14:21:29 +0100 Subject: [PATCH 208/753] updated version of unicase --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db2e9d983..d37c641b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,7 +321,7 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -341,7 +341,7 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -784,7 +784,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicase" -version = "1.3.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", From 5467b06c4f845bd8fde8adf216dec75deb4dbea6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 16:40:36 +0300 Subject: [PATCH 209/753] fix bench iter --- util/benches/bigint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 826d5023e..a22edcfbc 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -33,7 +33,7 @@ use ethcore_util::uint::*; fn u256_add(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256::from(1234599u64), |old, new| { old.overflowing_add(U256::from(new)).0 }) + (0..n).fold(U256([12345u64, 0u64, 0u64, 0u64]), |old, new| { old.overflowing_add(U256::from(new)).0 }) }); } @@ -42,7 +42,7 @@ fn u256_add(b: &mut Bencher) { fn u256_sub(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256::from(::std::u64::MAX), |old, new| { old.overflowing_sub(U256::from(new)).0 }) + (0..n).fold(U256([::std::u64::MAX, 0u64, 0u64, 0u64]), |old, new| { old.overflowing_sub(U256::from(new)).0 }) }); } From fb5779a00eeeef78228ec61e09331fbed503293a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 16:55:03 +0300 Subject: [PATCH 210/753] specific feature for asm opt --- util/Cargo.toml | 1 + util/src/lib.rs | 2 +- util/src/uint.rs | 12 ++++++------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/util/Cargo.toml b/util/Cargo.toml index 6d2ebcd9b..e2e91eb4b 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -39,6 +39,7 @@ target_info = "0.1" [features] default = [] dev = ["clippy"] +x64asm = [] [build-dependencies] vergen = "*" diff --git a/util/src/lib.rs b/util/src/lib.rs index 1f04240dc..d0c74af10 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -16,7 +16,7 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(feature="dev", feature(asm))] +#![cfg_attr(feature="x64asm", feature(asm))] #![cfg_attr(feature="dev", plugin(clippy))] // Clippy settings diff --git a/util/src/uint.rs b/util/src/uint.rs index 6869c3ec1..98c16ab90 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -51,7 +51,7 @@ macro_rules! impl_map_from { } } -#[cfg(not(all(feature="dev", target_arch = "x86_64")))] +#[cfg(not(all(feature="x64asm", target_arch = "x86_64")))] macro_rules! uint_overflowing_add { ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) @@ -89,7 +89,7 @@ macro_rules! uint_overflowing_add_reg { } -#[cfg(all(feature="dev", target_arch = "x86_64"))] +#[cfg(all(feature="x64asm", target_arch = "x86_64"))] macro_rules! uint_overflowing_add { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -119,7 +119,7 @@ macro_rules! uint_overflowing_add { ) } -#[cfg(not(all(feature="dev", target_arch = "x86_64")))] +#[cfg(not(all(feature="x64asm", target_arch = "x86_64")))] macro_rules! uint_overflowing_sub { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let res = overflowing!((!$other).overflowing_add(From::from(1u64))); @@ -128,7 +128,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(feature="dev", target_arch = "x86_64"))] +#[cfg(all(feature="x64asm", target_arch = "x86_64"))] macro_rules! uint_overflowing_sub { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -158,7 +158,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(feature="dev", target_arch = "x86_64"))] +#[cfg(all(feature="x64asm", target_arch = "x86_64"))] macro_rules! uint_overflowing_mul { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -283,7 +283,7 @@ macro_rules! uint_overflowing_mul { ) } -#[cfg(not(all(feature="dev", target_arch = "x86_64")))] +#[cfg(not(all(feature="x64asm", target_arch = "x86_64")))] macro_rules! uint_overflowing_mul { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) From 7525ff23cf1802cbeb6e4d51394eac3974de4c70 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 17:59:08 +0300 Subject: [PATCH 211/753] removed artefact cls/pushf/popf --- util/src/uint.rs | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 98c16ab90..bebaade22 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -168,7 +168,6 @@ macro_rules! uint_overflowing_mul { let overflow: u8; unsafe { asm!(" - clc mov $5, %rax mulq $9 mov %rax, $0 @@ -176,77 +175,59 @@ macro_rules! uint_overflowing_mul { mov $6, %rax mulq $9 - clc - adc %rax, $1 + add %rax, $1 mov %rdx, $2 mov $5, %rax - pushf mulq $10 - popf - adc %rax, $1 + add %rax, $1 adc %rdx, $2 mov $6, %rax mulq $10 - clc - adc %rax, $2 + add %rax, $2 mov %rdx, $3 mov $7, %rax mulq $9 - clc - adc %rax, $2 + add %rax, $2 adc %rdx, $3 mov $5, %rax mulq $11 - clc - adc %rax, $2 + add %rax, $2 adc %rdx, $3 mov $8, %rax - pushf mulq $9 - popf adc %rax, $3 adc $$0, %rdx mov %rdx, %rcx - clc mov $7, %rax - pushf mulq $10 - popf - adc %rax, $3 + add %rax, $3 adc $$0, %rdx or %rdx, %rcx - clc mov $6, %rax - pushf mulq $11 - popf - adc %rax, $3 + add %rax, $3 adc $$0, %rdx or %rdx, %rcx - clc mov $5, %rax - pushf mulq $12 - popf - adc %rax, $3 + add %rax, $3 adc $$0, %rdx or %rdx, %rcx - clc cmpq $$0, %rcx jne 2f mov $8, %rax cmpq $$0, %rax - setz %cl + sete %cl mov $7, %rax cmpq $$0, %rax @@ -264,7 +245,8 @@ macro_rules! uint_overflowing_mul { and %dl, %cl - 2: " + 2: + " : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), /* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow) From 864e7540742ebc1c408e9e2de57f96eee28d7c5b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 18:02:08 +0300 Subject: [PATCH 212/753] overflowing_sub in sub --- util/src/uint.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index bebaade22..6793376a0 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -765,9 +765,9 @@ macro_rules! construct_uint { #[inline] fn sub(self, other: $name) -> $name { - panic_on_overflow!(self < other); - let res = overflowing!((!other).overflowing_add(From::from(1u64))); - overflowing!(self.overflowing_add(res)) + let (result, overflow) = self.overflowing_sub(other); + panic_on_overflow!(overflow); + result } } From 5d22ad3fc8abe4617684213833550207ddca2c6b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 18:10:33 +0300 Subject: [PATCH 213/753] counter jump better --- util/src/uint.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 6793376a0..f4d5b5b76 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -222,8 +222,7 @@ macro_rules! uint_overflowing_mul { adc $$0, %rdx or %rdx, %rcx - cmpq $$0, %rcx - jne 2f + jrcxz 2f mov $8, %rax cmpq $$0, %rax @@ -234,6 +233,8 @@ macro_rules! uint_overflowing_mul { sete %dl or %dl, %cl + jrcxz 2f + mov $3, %rax cmpq $$0, %rax sete %dl From 2ee4a0c8c6ff29d6bbbc15752778590364d9bdb3 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 18:16:08 +0300 Subject: [PATCH 214/753] mistake of ne/jcxz --- util/src/uint.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index f4d5b5b76..6793376a0 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -222,7 +222,8 @@ macro_rules! uint_overflowing_mul { adc $$0, %rdx or %rdx, %rcx - jrcxz 2f + cmpq $$0, %rcx + jne 2f mov $8, %rax cmpq $$0, %rax @@ -233,8 +234,6 @@ macro_rules! uint_overflowing_mul { sete %dl or %dl, %cl - jrcxz 2f - mov $3, %rax cmpq $$0, %rax sete %dl From bed89d0740ffe39000291ae42f60a7778760930a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Feb 2016 16:32:34 +0100 Subject: [PATCH 215/753] Fixed sync tests --- sync/src/lib.rs | 4 ++-- sync/src/tests/helpers.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 9bf715f07..6f28fc320 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -34,14 +34,14 @@ //! use std::env; //! use std::sync::Arc; //! use util::network::{NetworkService, NetworkConfiguration}; -//! use ethcore::client::Client; +//! use ethcore::client::{Client, ClientConfig}; //! use ethsync::{EthSync, SyncConfig}; //! use ethcore::ethereum; //! //! fn main() { //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let dir = env::temp_dir(); -//! let client = Client::new(ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); +//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); //! EthSync::register(&mut service, SyncConfig::default(), client); //! } //! ``` diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 05b190573..6f4392104 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -15,8 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId}; -use ethcore::BlockQueueInfo; +use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId, BlockQueueInfo}; use ethcore::header::{Header as BlockHeader, BlockNumber}; use ethcore::error::*; use io::SyncIo; @@ -242,7 +241,8 @@ impl BlockChainClient for TestBlockChainClient { verified_queue_size: 0, unverified_queue_size: 0, verifying_queue_size: 0, - max_unverified: 0, + max_queue_size: 0, + max_mem_use: 0, mem_used: 0, } } From 0344f2b4c98373dd8745af4ddb1708a3e1a0fbbf Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Feb 2016 17:14:45 +0100 Subject: [PATCH 216/753] Block queue mem limit test --- ethcore/src/block_queue.rs | 22 ++++++++++++++++++++-- ethcore/src/tests/helpers.rs | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 0f5985f06..879798868 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -30,6 +30,9 @@ use util::panics::*; known_heap_size!(0, UnVerifiedBlock, VerifyingBlock, PreVerifiedBlock); +const MIN_MEM_LIMIT: usize = 16384; +const MIN_QUEUE_LIMIT: usize = 512; + /// Block queue configuration #[derive(Debug)] pub struct BlockQueueConfig { @@ -178,8 +181,8 @@ impl BlockQueue { deleting: deleting.clone(), processing: RwLock::new(HashSet::new()), empty: empty.clone(), - max_queue_size: config.max_queue_size, - max_mem_use: config.max_mem_use, + max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), + max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), } } @@ -480,4 +483,19 @@ mod tests { assert!(queue.queue_info().is_empty()); } + + #[test] + fn test_mem_limit() { + let spec = get_test_spec(); + let engine = spec.to_engine().unwrap(); + let mut config = BlockQueueConfig::default(); + config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000 + let mut queue = BlockQueue::new(config, Arc::new(engine), IoChannel::disconnected()); + assert!(!queue.queue_info().is_full()); + let mut blocks = get_good_dummy_block_seq(50); + for b in blocks.drain(..) { + queue.import_block(b).unwrap(); + } + assert!(queue.queue_info().is_full()); + } } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 510833f4d..808d2e5fb 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -253,6 +253,25 @@ pub fn get_temp_state_in(path: &Path) -> State { State::new(journal_db, U256::from(0u8)) } +pub fn get_good_dummy_block_seq(count: usize) -> Vec { + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + let mut parent = test_engine.spec().genesis_header().hash(); + let mut r = Vec::new(); + for i in 1 .. count + 1 { + let mut block_header = Header::new(); + block_header.gas_limit = decode(test_engine.spec().engine_params.get("minGasLimit").unwrap()); + block_header.difficulty = decode(test_engine.spec().engine_params.get("minimumDifficulty").unwrap()); + block_header.timestamp = i as u64; + block_header.number = i as u64; + block_header.parent_hash = parent; + block_header.state_root = test_engine.spec().genesis_header().state_root; + parent = block_header.hash(); + r.push(create_test_block(&block_header)); + } + r +} + pub fn get_good_dummy_block() -> Bytes { let mut block_header = Header::new(); let test_spec = get_test_spec(); From c139b6bcbbfd7abc51bf437d40a7cc9cc166ab30 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Feb 2016 17:48:23 +0100 Subject: [PATCH 217/753] Fixed json tests build --- ethcore/src/json_tests/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index a386e2854..89bd5da2b 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use super::test_common::*; -use client::{BlockChainClient,Client}; +use client::{BlockChainClient, Client, ClientConfig}; use pod_state::*; use block::Block; use ethereum; @@ -53,7 +53,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let temp = RandomTempPath::new(); { - let client = Client::new(spec, temp.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); assert_eq!(client.chain_info().best_block_hash, genesis_hash); for (b, is_valid) in blocks.into_iter() { if Block::is_good(&b) { From 600859ed04acd3650868f35bf4a1add4f983702d Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 19:58:09 +0300 Subject: [PATCH 218/753] [ci skip] flush --- util/src/uint.rs | 48 +++++++++++++----------------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 6793376a0..8e9172a04 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -165,7 +165,7 @@ macro_rules! uint_overflowing_mul { let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; - let overflow: u8; + let overflow: u64; unsafe { asm!(" mov $5, %rax @@ -222,25 +222,25 @@ macro_rules! uint_overflowing_mul { adc $$0, %rdx or %rdx, %rcx - cmpq $$0, %rcx + cmpq $$0, %rcx jne 2f mov $8, %rax cmpq $$0, %rax - sete %cl + setne %cl mov $7, %rax cmpq $$0, %rax - sete %dl + setne %dl or %dl, %cl mov $3, %rax cmpq $$0, %rax - sete %dl + setne %dl mov $2, %rax cmpq $$0, %rax - sete %bl + setne %bl or %bl, %dl and %dl, %cl @@ -253,7 +253,7 @@ macro_rules! uint_overflowing_mul { : /* $5 */ "m"(self_t[0]), /* $6 */ "m"(self_t[1]), /* $7 */ "m"(self_t[2]), /* $8 */ "m"(self_t[3]), /* $9 */ "m"(other_t[0]), /* $10 */ "m"(other_t[1]), /* $11 */ "m"(other_t[2]), /* $12 */ "m"(other_t[3]) - : "rax", "rdx" + : "rax", "rdx", "rbx" : ); @@ -740,23 +740,8 @@ macro_rules! construct_uint { type Output = $name; fn add(self, other: $name) -> $name { - let $name(ref me) = self; - let $name(ref you) = other; - let mut ret = [0u64; $n_words]; - let mut carry = [0u64; $n_words]; - let mut b_carry = false; - for i in 0..$n_words { - if i < $n_words - 1 { - ret[i] = me[i].wrapping_add(you[i]); - if ret[i] < me[i] { - carry[i + 1] = 1; - b_carry = true; - } - } else { - ret[i] = me[i] + you[i]; - } - } - if b_carry { $name(ret) + $name(carry) } else { $name(ret) } + let (result, _) = self.overflowing_add(other); + result } } @@ -765,8 +750,7 @@ macro_rules! construct_uint { #[inline] fn sub(self, other: $name) -> $name { - let (result, overflow) = self.overflowing_sub(other); - panic_on_overflow!(overflow); + let (result, _) = self.overflowing_sub(other); result } } @@ -775,15 +759,9 @@ macro_rules! construct_uint { type Output = $name; fn mul(self, other: $name) -> $name { - let mut res = $name::from(0u64); - // TODO: be more efficient about this - for i in 0..(2 * $n_words) { - let v = self.mul_u32((other >> (32 * i)).low_u32()); - let (r, overflow) = v.overflowing_shl(32 * i as u32); - panic_on_overflow!(overflow); - res = res + r; - } - res + let (result, overflow) = self.overflowing_mul(other); + panic_on_overflow!(overflow); + result } } From 937547f178a1d0b8a0e4a730a938561361381b03 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 25 Feb 2016 20:20:00 +0100 Subject: [PATCH 219/753] rocksdb dependency version bump --- Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 424df8113..9bed0008a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,7 +154,7 @@ version = "0.5.4" source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -233,7 +233,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.3.0 (git+https://github.com/arkpar/rust-rocksdb.git)", + "rocksdb 0.4.0 (git+https://github.com/arkpar/rust-rocksdb.git)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -268,7 +268,7 @@ dependencies = [ [[package]] name = "gcc" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -419,8 +419,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librocksdb-sys" -version = "0.1.0" -source = "git+https://github.com/arkpar/rust-rocksdb.git#4986bcec0d2907ebd2cae64c6753cf9291b08e86" +version = "0.2.0" +source = "git+https://github.com/arkpar/rust-rocksdb.git#bf61c18ca933850f68b730ce13d592fba6e88039" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -588,11 +588,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" -version = "0.3.0" -source = "git+https://github.com/arkpar/rust-rocksdb.git#4986bcec0d2907ebd2cae64c6753cf9291b08e86" +version = "0.4.0" +source = "git+https://github.com/arkpar/rust-rocksdb.git#bf61c18ca933850f68b730ce13d592fba6e88039" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "librocksdb-sys 0.1.0 (git+https://github.com/arkpar/rust-rocksdb.git)", + "librocksdb-sys 0.2.0 (git+https://github.com/arkpar/rust-rocksdb.git)", ] [[package]] @@ -600,7 +600,7 @@ name = "rust-crypto" version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -666,7 +666,7 @@ dependencies = [ name = "sha3" version = "0.1.0" dependencies = [ - "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] From e946e2ab183f8c1c60d88769602e654911244396 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 22:27:22 +0300 Subject: [PATCH 220/753] epic mul overflow bug --- util/src/uint.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 8e9172a04..f9d9b4af8 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -225,25 +225,17 @@ macro_rules! uint_overflowing_mul { cmpq $$0, %rcx jne 2f - mov $8, %rax - cmpq $$0, %rax - setne %cl + popcnt $8, %rcx + popcnt $7, %rax + add %rax, %rcx + jrcxz 2f - mov $7, %rax - cmpq $$0, %rax - setne %dl - or %dl, %cl + popcnt $12, %rcx + popcnt $11, %rax + add %rax, %rcx + jrcxz 2f - mov $3, %rax - cmpq $$0, %rax - setne %dl - - mov $2, %rax - cmpq $$0, %rax - setne %bl - or %bl, %dl - - and %dl, %cl + mov $$1, %rcx 2: " @@ -740,7 +732,8 @@ macro_rules! construct_uint { type Output = $name; fn add(self, other: $name) -> $name { - let (result, _) = self.overflowing_add(other); + let (result, overflow) = self.overflowing_add(other); + panic_on_overflow!(overflow); result } } @@ -750,7 +743,8 @@ macro_rules! construct_uint { #[inline] fn sub(self, other: $name) -> $name { - let (result, _) = self.overflowing_sub(other); + let (result, overflow) = self.overflowing_sub(other); + panic_on_overflow!(overflow); result } } From 4b0ec642995206fcef7cca18b8a3cec733813be3 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 25 Feb 2016 22:48:34 +0300 Subject: [PATCH 221/753] random init for benches --- util/benches/bigint.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index a22edcfbc..3b2012bc7 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -25,6 +25,7 @@ extern crate test; extern crate ethcore_util; +extern crate rand; use test::{Bencher, black_box}; use ethcore_util::uint::*; @@ -33,7 +34,7 @@ use ethcore_util::uint::*; fn u256_add(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256([12345u64, 0u64, 0u64, 0u64]), |old, new| { old.overflowing_add(U256::from(new)).0 }) + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), |old, new| { old.overflowing_add(U256::from(new)).0 }) }); } @@ -42,7 +43,7 @@ fn u256_add(b: &mut Bencher) { fn u256_sub(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256([::std::u64::MAX, 0u64, 0u64, 0u64]), |old, new| { old.overflowing_sub(U256::from(new)).0 }) + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), |old, new| { old.overflowing_sub(U256::from(new)).0 }) }); } @@ -50,7 +51,7 @@ fn u256_sub(b: &mut Bencher) { fn u256_mul(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U256([12345u64, 0u64, 0u64, 0u64]), |old, new| { old.overflowing_mul(U256::from(new)).0 }) + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), |old, new| { old.overflowing_mul(U256::from(new)).0 }) }); } From c76fc14a5cd2db0a8d3e518943e2c3c6613dce12 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 26 Feb 2016 03:22:18 +0100 Subject: [PATCH 222/753] rocksdb dependency version bump --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index faf345dc0..40fcb6627 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,7 +234,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.4.0 (git+https://github.com/arkpar/rust-rocksdb.git)", + "rocksdb 0.4.1 (git+https://github.com/arkpar/rust-rocksdb.git)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -426,8 +426,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librocksdb-sys" -version = "0.2.0" -source = "git+https://github.com/arkpar/rust-rocksdb.git#bf61c18ca933850f68b730ce13d592fba6e88039" +version = "0.2.1" +source = "git+https://github.com/arkpar/rust-rocksdb.git#2156621f583bda95c1c07e89e79e4019f75158ee" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -636,11 +636,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" -version = "0.4.0" -source = "git+https://github.com/arkpar/rust-rocksdb.git#bf61c18ca933850f68b730ce13d592fba6e88039" +version = "0.4.1" +source = "git+https://github.com/arkpar/rust-rocksdb.git#2156621f583bda95c1c07e89e79e4019f75158ee" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "librocksdb-sys 0.2.0 (git+https://github.com/arkpar/rust-rocksdb.git)", + "librocksdb-sys 0.2.1 (git+https://github.com/arkpar/rust-rocksdb.git)", ] [[package]] From 5545cbc6bc6a910faa4a4f5225afc24e396be45c Mon Sep 17 00:00:00 2001 From: Wojciech Langiewicz Date: Fri, 26 Feb 2016 10:07:30 +0100 Subject: [PATCH 223/753] ignore intellij idea project files as well --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 90750f379..58b1895c6 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ # jetbrains ide stuff .idea +*.iml From c66178e3f7c90b483f4f5a9fceeda0752f888235 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 26 Feb 2016 11:37:06 +0100 Subject: [PATCH 224/753] Fixed a race condition when a connecting peer disconnects immediately --- sync/src/chain.rs | 13 ++++++------- util/src/network/host.rs | 12 ++++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index f76978bda..930518007 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -555,7 +555,10 @@ impl ChainSync { /// Called when a new peer is connected pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { trace!(target: "sync", "== Connected {}", peer); - self.send_status(io, peer); + if let Err(e) = self.send_status(io) { + warn!(target:"sync", "Error sending status request: {:?}", e); + io.disable_peer(peer); + } } /// Resume downloading @@ -887,7 +890,7 @@ impl ChainSync { } /// Send Status message - fn send_status(&mut self, io: &mut SyncIo, peer_id: PeerId) { + fn send_status(&mut self, io: &mut SyncIo) -> Result<(), UtilError> { let mut packet = RlpStream::new_list(5); let chain = io.chain().chain_info(); packet.append(&(PROTOCOL_VERSION as u32)); @@ -895,11 +898,7 @@ impl ChainSync { packet.append(&chain.total_difficulty); packet.append(&chain.best_block_hash); packet.append(&chain.genesis_hash); - //TODO: handle timeout for status request - if let Err(e) = io.send(peer_id, STATUS_PACKET, packet.out()) { - warn!(target:"sync", "Error sending status request: {:?}", e); - io.disable_peer(peer_id); - } + io.respond(STATUS_PACKET, packet.out()) } /// Respond to GetBlockHeaders request diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 8dd9eb9cc..d50f2d86d 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -579,7 +579,7 @@ impl Host where Message: Send + Sync + Clone { } } if kill { - self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection + self.kill_connection(token, io, true); return; } else if create_session { self.start_session(token, io); @@ -621,7 +621,7 @@ impl Host where Message: Send + Sync + Clone { } } if kill { - self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection + self.kill_connection(token, io, true); } for p in ready_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); @@ -685,6 +685,7 @@ impl Host where Message: Send + Sync + Clone { fn kill_connection(&self, token: StreamToken, io: &IoContext>, remote: bool) { let mut to_disconnect: Vec = Vec::new(); let mut failure_id = None; + let mut deregister = false; match token { FIRST_HANDSHAKE ... LAST_HANDSHAKE => { let handshakes = self.handshakes.write().unwrap(); @@ -693,7 +694,7 @@ impl Host where Message: Send + Sync + Clone { if !handshake.expired() { handshake.set_expired(); failure_id = Some(handshake.id().clone()); - io.deregister_stream(token).expect("Error deregistering stream"); + deregister = true; } } }, @@ -711,7 +712,7 @@ impl Host where Message: Send + Sync + Clone { } s.set_expired(); failure_id = Some(s.id().clone()); - io.deregister_stream(token).expect("Error deregistering stream"); + deregister = true; } } }, @@ -726,6 +727,9 @@ impl Host where Message: Send + Sync + Clone { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); h.disconnected(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token); } + if deregister { + io.deregister_stream(token).expect("Error deregistering stream"); + } } fn update_nodes(&self, io: &IoContext>, node_changes: TableUpdates) { From f29417eea91f689fe57d3d8b06e1921b93235291 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 14:50:55 +0300 Subject: [PATCH 225/753] allow dead code for macros expansion --- util/src/uint.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/src/uint.rs b/util/src/uint.rs index f9d9b4af8..ca727190b 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -588,6 +588,7 @@ macro_rules! construct_uint { } impl $name { + #[allow(dead_code)] // not used when multiplied with inline assembly /// Multiplication by u32 fn mul_u32(self, other: u32) -> Self { let $name(ref arr) = self; @@ -609,6 +610,7 @@ macro_rules! construct_uint { $name(ret) + $name(carry) } + #[allow(dead_code)] // not used when multiplied with inline assembly /// Overflowing multiplication by u32 fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { let $name(ref arr) = self; From 80d60cedf6f43b7cc3d03485f1c5be3202dec5f4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 26 Feb 2016 13:27:05 +0100 Subject: [PATCH 226/753] Removed rocksdb from build scripts and instructions --- README.md | 25 +-------------------- ethcore/src/lib.rs | 13 ++--------- install-deps.sh | 55 +--------------------------------------------- install-parity.sh | 50 ++++++++++++++++------------------------- 4 files changed, 23 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index 4df7cad34..575234622 100644 --- a/README.md +++ b/README.md @@ -18,17 +18,9 @@ ##### Ubuntu 14.04, 15.04, 15.10 ```bash -# install rocksdb -add-apt-repository ppa:ethcore/ethcore -apt-get update -apt-get install -y --force-yes librocksdb-dev - # install multirust curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install beta -multirust update beta - # download and build parity git clone https://github.com/ethcore/parity cd parity @@ -43,20 +35,9 @@ cargo build --release ##### Other Linux ```bash -# install rocksdb -git clone --tag v4.1 --depth=1 https://github.com/facebook/rocksdb.git -cd rocksdb -make shared_lib -sudo cp -a librocksdb.so* /usr/lib -sudo ldconfig -cd .. - # install rust beta curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes -# install beta -multirust update beta - # download and build parity git clone https://github.com/ethcore/parity cd parity @@ -71,14 +52,10 @@ cargo build --release ##### OSX with Homebrew ```bash -# install rocksdb && multirust +# install multirust brew update -brew install rocksdb brew install multirust -# install beta -multirust update beta - # download and build parity git clone https://github.com/ethcore/parity cd parity diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index d4786bc21..5eb3beeb2 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -40,23 +40,17 @@ //! - Ubuntu 14.04 and later: //! //! ```bash -//! # install rocksdb -//! add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" -//! apt-get update -//! apt-get install -y --force-yes librocksdb //! //! # install multirust //! curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes //! -//! # install nightly and make it default -//! multirust update nightly && multirust default nightly -//! //! # export rust LIBRARY_PATH //! export LIBRARY_PATH=/usr/local/lib //! //! # download and build parity //! git clone https://github.com/ethcore/parity //! cd parity +//! multirust override beta //! cargo build --release //! ``` //! @@ -65,18 +59,15 @@ //! ```bash //! # install rocksdb && multirust //! brew update -//! brew install rocksdb //! brew install multirust //! -//! # install nightly and make it default -//! multirust update nightly && multirust default nightly -//! //! # export rust LIBRARY_PATH //! export LIBRARY_PATH=/usr/local/lib //! //! # download and build parity //! git clone https://github.com/ethcore/parity //! cd parity +//! multirust override beta //! cargo build --release //! ``` diff --git a/install-deps.sh b/install-deps.sh index f5e1e44cf..6cc7de002 100755 --- a/install-deps.sh +++ b/install-deps.sh @@ -342,8 +342,6 @@ function run_installer() exe brew update echo - info "Installing rocksdb" - exe brew install rocksdb info "Installing multirust" exe brew install multirust sudo multirust default beta @@ -391,7 +389,6 @@ function run_installer() linux_version find_multirust - find_rocksdb find_curl find_git @@ -402,21 +399,6 @@ function run_installer() find_sudo } - function find_rocksdb() - { - depCount=$((depCount+1)) - if [[ $(ldconfig -v 2>/dev/null | grep rocksdb | wc -l) == 1 ]]; then - depFound=$((depFound+1)) - check "apt-get" - isRocksDB=true - INSTALL_FILES+="${blue}${dim}==> librocksdb:${reset}$n" - else - uncheck "librocksdb is missing" - isRocksDB=false - INSTALL_FILES+="${blue}${dim}==> librocksdb:${reset}$n" - fi - } - function find_multirust() { depCount=$((depCount+2)) @@ -562,34 +544,6 @@ function run_installer() fi } - function ubuntu_rocksdb_installer() - { - sudo apt-get update -qq - sudo apt-get install -qq -y software-properties-common - sudo apt-add-repository -y ppa:ethcore/ethcore - sudo apt-get -f -y install - sudo apt-get update -qq - sudo apt-get install -qq -y librocksdb-dev librocksdb - } - - function linux_rocksdb_installer() - { - if [[ $isUbuntu == true ]]; then - ubuntu_rocksdb_installer - else - oldpwd=`pwd` - cd /tmp - exe git clone --branch v4.2 --depth=1 https://github.com/facebook/rocksdb.git - cd rocksdb - exe make shared_lib - sudo cp -a librocksdb.so* /usr/lib - sudo ldconfig - cd /tmp - rm -rf /tmp/rocksdb - cd $oldpwd - fi - } - function linux_installer() { if [[ $isGCC == false || $isGit == false || $isMake == false || $isCurl == false ]]; then @@ -610,12 +564,6 @@ function run_installer() echo fi - if [[ $isRocksDB == false ]]; then - info "Installing rocksdb..." - linux_rocksdb_installer - echo - fi - if [[ $isMultirust == false ]]; then info "Installing multirust..." if [[ $isSudo == false ]]; then @@ -655,10 +603,9 @@ function run_installer() find_git find_make find_gcc - find_rocksdb find_multirust - if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isRocksDB == false || $isMultirustBeta == false ]]; then + if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isMultirustBeta == false ]]; then abort_install fi fi diff --git a/install-parity.sh b/install-parity.sh index 60d3471d5..439700306 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -236,14 +236,29 @@ function run_installer() { linux_version - find_rocksdb - find_curl find_apt find_sudo } + function find_git() + { + depCount=$((depCount+1)) + GIT_PATH=`which git 2>/dev/null` + + if [[ -f $GIT_PATH ]] + then + depFound=$((depFound+1)) + check "git" + isGit=true + else + uncheck "git is missing" + isGit=false + INSTALL_FILES+="${blue}${dim}==> git:${reset}${n}" + fi + } + function find_brew() { BREW_PATH=`which brew 2>/dev/null` @@ -333,20 +348,6 @@ function run_installer() fi } - function find_rocksdb() - { - depCount=$((depCount+1)) - if [[ $(ldconfig -v 2>/dev/null | grep rocksdb | wc -l) == 1 ]]; then - depFound=$((depFound+1)) - check "librocksdb" - isRocksDB=true - else - uncheck "librocksdb is missing" - isRocksDB=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tlibrocksdb${n}" - fi - } - function find_apt() { depCount=$((depCount+1)) @@ -386,10 +387,9 @@ function run_installer() info "Verifying installation" if [[ $OS_TYPE == "linux" ]]; then - find_rocksdb find_apt - if [[ $isRocksDB == false || $isApt == false ]]; then + if [[ $isApt == false ]]; then abortInstall fi fi @@ -397,23 +397,11 @@ function run_installer() function linux_deps_installer() { - if [[ $isRocksDB == false || $isCurl == false ]]; then + if [[ $isCurl == false ]]; then info "Preparing apt..." sudo apt-get update -qq echo fi - - if [[ $isRocksDB == false ]]; then - info "Installing rocksdb..." - - sudo apt-get install -qq -y software-properties-common - sudo apt-add-repository -y ppa:ethcore/ethcore - sudo apt-get -f -y install - sudo apt-get update -qq - sudo apt-get install -qq -y librocksdb - - echo - fi if [[ $isCurl == false ]]; then info "Installing curl..." From e95538f3ec716af0e051b6ed88761105b598defd Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 15:56:55 +0300 Subject: [PATCH 227/753] [ci skip] style fixes, multipart add test --- util/src/uint.rs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index ca727190b..82d3afe97 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -51,7 +51,7 @@ macro_rules! impl_map_from { } } -#[cfg(not(all(feature="x64asm", target_arch = "x86_64")))] +#[cfg(not(all(feature="x64asm", target_arch="x86_64")))] macro_rules! uint_overflowing_add { ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) @@ -89,7 +89,7 @@ macro_rules! uint_overflowing_add_reg { } -#[cfg(all(feature="x64asm", target_arch = "x86_64"))] +#[cfg(all(feature="x64asm", target_arch="x86_64"))] macro_rules! uint_overflowing_add { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -119,7 +119,7 @@ macro_rules! uint_overflowing_add { ) } -#[cfg(not(all(feature="x64asm", target_arch = "x86_64")))] +#[cfg(not(all(feature="x64asm", target_arch="x86_64")))] macro_rules! uint_overflowing_sub { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let res = overflowing!((!$other).overflowing_add(From::from(1u64))); @@ -128,7 +128,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(feature="x64asm", target_arch = "x86_64"))] +#[cfg(all(feature="x64asm", target_arch="x86_64"))] macro_rules! uint_overflowing_sub { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -158,7 +158,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(feature="x64asm", target_arch = "x86_64"))] +#[cfg(all(feature="x64asm", target_arch="x86_64"))] macro_rules! uint_overflowing_mul { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -222,7 +222,7 @@ macro_rules! uint_overflowing_mul { adc $$0, %rdx or %rdx, %rcx - cmpq $$0, %rcx + cmpq $$0, %rcx jne 2f popcnt $8, %rcx @@ -257,7 +257,7 @@ macro_rules! uint_overflowing_mul { ) } -#[cfg(not(all(feature="x64asm", target_arch = "x86_64")))] +#[cfg(not(all(feature="x64asm", target_arch="x86_64")))] macro_rules! uint_overflowing_mul { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) @@ -1468,5 +1468,26 @@ mod tests { fn display_uint_zero() { assert_eq!(format!("{}", U256::from(0)), "0"); } + + + #[test] + fn u256_multi_adds() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_add(U256([0, 0, 0, 0])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_add(U256([0, 0, 0, 1])); + assert_eq!(result, U256([0, 0, 0, 2])); + + let (result, overflow) = U256([0, 0, 2, 1]).overflowing_add(U256([0, 0, 3, 1])); + assert_eq!(result, U256([0, 0, 5, 2])); + assert!(!overflow); + + let (_, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_add(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_add(U256([0, 0, 0, ::std::u64::MAX])); + assert!(overflow); + } } From 228e3fefe02445b39ce227d182331483beb90dd5 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 16:03:04 +0300 Subject: [PATCH 228/753] [ci skip] multipart sub test --- util/src/uint.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/util/src/uint.rs b/util/src/uint.rs index 82d3afe97..245381b4b 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1489,5 +1489,32 @@ mod tests { let (_, overflow) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_add(U256([0, 0, 0, ::std::u64::MAX])); assert!(overflow); } + + + #[test] + fn u256_multi_subs() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_sub(U256([0, 0, 0, 0])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 0, 1])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (_, overflow) = U256([0, 0, 2, 1]).overflowing_sub(U256([0, 0, 3, 1])); + assert!(overflow); + + let (result, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_sub(U256([::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1]), result); + + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 1, 0])); + assert!(!overflow); + assert_eq!(U256([0, 0, ::std::u64::MAX, 0]), result); + + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([1, 0, 0, 0])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + } + } From 3858a2011fb765dbb785f15773f21bb4578548f6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 16:12:47 +0300 Subject: [PATCH 229/753] [ci skip] mul multipart tests --- util/src/uint.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/util/src/uint.rs b/util/src/uint.rs index 245381b4b..a34742bd9 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1516,5 +1516,51 @@ mod tests { assert_eq!(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]), result); } + + #[test] + fn u256_multi_muls() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([1, 0, 0, 0]), result); + + let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); + assert_eq!(U256([25, 0, 0, 0]), result); + + let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 25, 0]), result); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 1]), result); + + let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 10]), result); + + let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 0, 5]), result); + + let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 10, 0, 0]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX-1, 0, 0]), result); + + let (result, _) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, 0, 0]), result); + } + + + } From 023c6236500b82f89110c0f482e15b23a559cbb5 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 16:19:55 +0300 Subject: [PATCH 230/753] mul overflow multipart test --- util/src/uint.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/util/src/uint.rs b/util/src/uint.rs index a34742bd9..98541fe33 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1560,7 +1560,34 @@ mod tests { assert_eq!(U256([1, 0, 0, 0]), result); } + #[test] + fn u256_multi_muls_overflow() { + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert!(!overflow); + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(!overflow); + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(!overflow); + + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 1, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([0, 1, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 1, 0, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([0, ::std::u64::MAX, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([10, 0, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX / 2])); + assert!(!overflow); + + let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert!(overflow); + } } From 5013c4d1f1efc38e2237ed691e48f9e3f5e54aa0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 16:50:12 +0300 Subject: [PATCH 231/753] naughty overflow bug fixed --- util/src/uint.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index 98541fe33..b4940cfb8 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -226,16 +226,30 @@ macro_rules! uint_overflowing_mul { jne 2f popcnt $8, %rcx - popcnt $7, %rax - add %rax, %rcx - jrcxz 2f + jrcxz 12f popcnt $12, %rcx popcnt $11, %rax add %rax, %rcx - jrcxz 2f + popcnt $10, %rax + add %rax, %rcx + jmp 2f - mov $$1, %rcx + 12: + popcnt $12, %rcx + jrcxz 11f + + popcnt $7, %rcx + popcnt $6, %rax + add %rax, %rcx + + cmpq $$0, %rcx + jne 2f + + 11: + popcnt $11, %rcx + jrcxz 2f + popcnt $7, %rcx 2: " @@ -1569,7 +1583,7 @@ mod tests { assert!(!overflow); let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert!(!overflow); + assert!(overflow); let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 1, 0, 0])); assert!(!overflow); From 3750a8964c0424387cdf545a6d1a4f7dd5035147 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 17:48:50 +0300 Subject: [PATCH 232/753] removed redundant clones --- util/src/keys/geth_import.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/util/src/keys/geth_import.rs b/util/src/keys/geth_import.rs index 61df88589..2ee3c987c 100644 --- a/util/src/keys/geth_import.rs +++ b/util/src/keys/geth_import.rs @@ -63,12 +63,13 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) let mut buf = String::new(); try!(file.read_to_string(&mut buf)); - let mut json = match Json::from_str(&buf) { - Ok(parsed_json) => try!(parsed_json.as_object().ok_or(ImportError::FormatError)).clone(), + let mut json_result = Json::from_str(&buf); + let mut json = match json_result { + Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::FormatError)), Err(_) => { return Err(ImportError::FormatError); } }; let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::FormatError)).clone(); - json.insert("crypto".to_owned(), Json::Object(crypto_object.clone())); + json.insert("crypto".to_owned(), Json::Object(crypto_object)); json.remove("Crypto"); match KeyFileContent::load(&Json::Object(json.clone())) { Ok(key_file) => try!(secret_store.import_key(key_file)), From fd63fa6836489039756f105086b8b41fac793dad Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Feb 2016 17:27:56 +0100 Subject: [PATCH 233/753] Update block.rs --- ethcore/src/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 9051b6d9a..70c6c2fb2 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -144,7 +144,7 @@ impl IsBlock for ExecutedBlock { /// Block that is ready for transactions to be added. /// -/// It's a bit like a Vec, eccept that whenever a transaction is pushed, we execute it and +/// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and /// maintain the system `state()`. We also archive execution receipts in preparation for later block creation. pub struct OpenBlock<'x> { block: ExecutedBlock, From f118e30b209074236c4593693d3285c032ed2bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 26 Feb 2016 19:56:32 +0100 Subject: [PATCH 234/753] Renaming variables to more descriptive --- ethcore/src/block_queue.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index ff20021f2..62763386f 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -285,14 +285,14 @@ impl BlockQueue { } /// Mark given block and all its children as bad. Stops verification. - pub fn mark_as_bad(&mut self, hashes: &[H256]) { + pub fn mark_as_bad(&mut self, block_hashes: &[H256]) { let mut verification_lock = self.verification.lock().unwrap(); let mut processing = self.processing.write().unwrap(); let mut verification = verification_lock.deref_mut(); - verification.bad.reserve(hashes.len()); - for hash in hashes { + verification.bad.reserve(block_hashes.len()); + for hash in block_hashes { verification.bad.insert(hash.clone()); processing.remove(&hash); } @@ -310,10 +310,10 @@ impl BlockQueue { } /// Mark given block as processed - pub fn mark_as_good(&mut self, hashes: &[H256]) { + pub fn mark_as_good(&mut self, block_hashes: &[H256]) { let mut processing = self.processing.write().unwrap(); - for h in hashes { - processing.remove(&h); + for hash in block_hashes { + processing.remove(&hash); } } From 9585138f20fdf74c327c484fa7e1a1a24f4393e2 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 23:24:04 +0300 Subject: [PATCH 235/753] add/sub 512 --- util/src/uint.rs | 179 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 159 insertions(+), 20 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index b4940cfb8..5a2730126 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -97,23 +97,69 @@ macro_rules! uint_overflowing_add { let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; let overflow: u8; - unsafe { - asm!(" - adc $9, $0 - adc $10, $1 - adc $11, $2 - adc $12, $3 - setc %al - " - : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) - : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + unsafe { + asm!(" + add $9, $0 + adc $10, $1 + adc $11, $2 + adc $12, $3 + setc %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) - : - : + : + : ); } (U256(result), overflow != 0) }); + (U512, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 8] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 8] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 8] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + + unsafe { + asm!(" + add $15, $0 + adc $16, $1 + adc $17, $2 + adc $18, $3 + lodsq + adc $11, %rax + stosq + lodsq + adc $12, %rax + stosq + lodsq + adc $13, %rax + stosq + lodsq + adc $14, %rax + stosq + setc %al + + ": "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), + + "={al}"(overflow) /* $0 - $4 */ + + : "{rdi}"(&result[4] as *const u64) /* $5 */ + "{rsi}"(&other_t[4] as *const u64) /* $6 */ + "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + "m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]), + /* $7 - $14 */ + + "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]), + "m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */ + : "rdi", "rsi" + : + ); + } + (U512(result), overflow != 0) + }); + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) ) @@ -138,12 +184,13 @@ macro_rules! uint_overflowing_sub { let overflow: u8; unsafe { asm!(" - sbb $9, $0 - sbb $10, $1 - sbb $11, $2 - sbb $12, $3 - setb %al" - : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + sub $9, $0 + sbb $10, $1 + sbb $11, $2 + sbb $12, $3 + setb %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) : : @@ -151,6 +198,51 @@ macro_rules! uint_overflowing_sub { } (U256(result), overflow != 0) }); + (U512, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 8] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 8] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 8] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + + unsafe { + asm!(" + sub $15, $0 + sbb $16, $1 + sbb $17, $2 + sbb $18, $3 + lodsq + sbb $19, %rax + stosq + lodsq + sbb $20, %rax + stosq + lodsq + sbb $21, %rax + stosq + lodsq + sbb $22, %rax + stosq + setb %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), + + "={al}"(overflow) /* $0 - $4 */ + + : "{rdi}"(&result[4] as *const u64) /* $5 */ + "{rsi}"(&self_t[4] as *const u64) /* $6 */ + "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + "m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]), + /* $7 - $14 */ + + "m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]), + "m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */ + : "rdi", "rsi" + : + ); + } + (U512(result), overflow != 0) + }); ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let res = overflowing!((!$other).overflowing_add(From::from(1u64))); let res = overflowing!($self_expr.overflowing_add(res)); @@ -251,8 +343,8 @@ macro_rules! uint_overflowing_mul { jrcxz 2f popcnt $7, %rcx - 2: - " + 2: + " : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), /* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow) @@ -1483,6 +1575,38 @@ mod tests { assert_eq!(format!("{}", U256::from(0)), "0"); } + #[test] + fn u512_multi_adds() { + let (result, _) = U512([0, 0, 0, 0, 0, 0, 0, 0]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, 0])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 0, 0])); + + let (result, _) = U512([1, 0, 0, 0, 0, 0, 0, 1]).overflowing_add(U512([1, 0, 0, 0, 0, 0, 0, 1])); + assert_eq!(result, U512([2, 0, 0, 0, 0, 0, 0, 2])); + + let (result, _) = U512([0, 0, 0, 0, 0, 0, 0, 1]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, 1])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 0, 2])); + + let (result, _) = U512([0, 0, 0, 0, 0, 0, 2, 1]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 3, 1])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 5, 2])); + + let (result, _) = U512([1, 2, 3, 4, 5, 6, 7, 8]).overflowing_add(U512([9, 10, 11, 12, 13, 14, 15, 16])); + assert_eq!(result, U512([10, 12, 14, 16, 18, 20, 22, 24])); + + let (_, overflow) = U512([0, 0, 0, 0, 0, 0, 2, 1]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 3, 1])); + assert!(!overflow); + + let (_, overflow) = U512([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_add(U512([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U512([0, 0, 0, 0, 0, 0, 0, ::std::u64::MAX]) + .overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U512([0, 0, 0, 0, 0, 0, 0, ::std::u64::MAX]) + .overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, 0])); + assert!(!overflow); + } #[test] fn u256_multi_adds() { @@ -1531,6 +1655,21 @@ mod tests { } + #[test] + fn u512_multi_subs() { + let (result, _) = U512([0, 0, 0, 0, 0, 0, 0, 0]).overflowing_sub(U512([0, 0, 0, 0, 0, 0, 0, 0])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 0, 0])); + + let (result, _) = U512([10, 9, 8, 7, 6, 5, 4, 3]).overflowing_sub(U512([9, 8, 7, 6, 5, 4, 3, 2])); + assert_eq!(result, U512([1, 1, 1, 1, 1, 1, 1, 1])); + + let (_, overflow) = U512([10, 9, 8, 7, 6, 5, 4, 3]).overflowing_sub(U512([9, 8, 7, 6, 5, 4, 3, 2])); + assert!(!overflow); + + let (_, overflow) = U512([9, 8, 7, 6, 5, 4, 3, 2]).overflowing_sub(U512([10, 9, 8, 7, 6, 5, 4, 3])); + assert!(overflow); + } + #[test] fn u256_multi_muls() { let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); From 98a75d06d16c2e2924ce4d3bc6f950f87e4753b4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 26 Feb 2016 23:37:13 +0300 Subject: [PATCH 236/753] benches --- util/benches/bigint.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 3b2012bc7..da82084b8 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -38,7 +38,6 @@ fn u256_add(b: &mut Bencher) { }); } - #[bench] fn u256_sub(b: &mut Bencher) { b.iter(|| { @@ -47,6 +46,25 @@ fn u256_sub(b: &mut Bencher) { }); } +#[bench] +fn u512_sub(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U512([rand::random::(), rand::random::(), rand::random::(), rand::random::(), + rand::random::(), rand::random::(), rand::random::(), rand::random::()]), + |old, new| { old.overflowing_sub(U512([0, 0, 0, 0, 0, 0, 0, new])).0 }) + }); +} + +#[bench] +fn u512_add(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U512([0, 0, 0, 0, 0, 0, 0, 0]), + |old, new| { old.overflowing_add(U512([new, new, new, new, new, new, new, new])).0 }) + }); +} + #[bench] fn u256_mul(b: &mut Bencher) { b.iter(|| { From 52faf8164d36d627bbdfde3f634ada216bf8e525 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Feb 2016 21:38:05 +0100 Subject: [PATCH 237/753] Update store.rs --- util/src/keys/store.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 3b1ca4727..c4fa377f9 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -64,7 +64,8 @@ impl SecretStore { /// new instance of Secret Store in default home directory pub fn new() -> SecretStore { let mut path = ::std::env::home_dir().expect("Failed to get home dir"); - path.push("keystore"); + path.push(".parity"); + path.push("keys"); Self::new_in(&path) } From 5d5471f981a02915aa4be2626e63ed452364e40a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Feb 2016 22:40:32 +0100 Subject: [PATCH 238/753] Fix minor typo. --- parity/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index b50994cb9..c0c260371 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -71,8 +71,8 @@ Options: --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect. --address URL Equivalent to --listen-address URL --public-address URL. - --peers NUM Try to maintain that many peers [default: 25]. - --no-discovery Disable new peer discovery. + --peers NUM Try to maintain that many peers [default: 25]. + --no-discovery Disable new peer discovery. --no-upnp Disable trying to figure out the correct public adderss over UPnP. --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. From 9b244022c7988da47674b380a903cd04e65b3498 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 26 Feb 2016 22:44:33 +0100 Subject: [PATCH 239/753] Fix up README. --- README.md | 48 +++++++++++------------------------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 575234622..f8b24f088 100644 --- a/README.md +++ b/README.md @@ -15,54 +15,28 @@ ### Building from source -##### Ubuntu 14.04, 15.04, 15.10 +First (if you don't already have it) get multirust: +- Linux: ```bash -# install multirust -curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes - -# download and build parity -git clone https://github.com/ethcore/parity -cd parity - -# parity should be build with rust beta -multirust override beta - -# build in release -cargo build --release -``` - -##### Other Linux - -```bash -# install rust beta curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes - -# download and build parity -git clone https://github.com/ethcore/parity -cd parity - -# parity should be build with rust beta -multirust override beta - -# build in release -cargo build --release ``` -##### OSX with Homebrew +- OSX with Homebrew: +```bash +brew update && brew install multirust +``` + +Then, download and build Parity: ```bash -# install multirust -brew update -brew install multirust - -# download and build parity +# download Parity code git clone https://github.com/ethcore/parity cd parity -# use rust beta for building parity +# parity should be built with rust beta multirust override beta +# build in release mode cargo build --release ``` - From 53e8d990755125f5370a28dd630721f2498fa3e1 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 01:37:12 +0100 Subject: [PATCH 240/753] blockchain split into few separate submodules, cleanup insert_block process --- ethcore/src/blockchain/best_block.rs | 23 ++ ethcore/src/blockchain/block_info.rs | 19 + ethcore/src/{ => blockchain}/blockchain.rs | 420 ++++++++++----------- ethcore/src/blockchain/bloom_indexer.rs | 43 +++ ethcore/src/blockchain/cache.rs | 23 ++ ethcore/src/blockchain/mod.rs | 10 + ethcore/src/blockchain/tree_route.rs | 13 + ethcore/src/client.rs | 6 +- 8 files changed, 332 insertions(+), 225 deletions(-) create mode 100644 ethcore/src/blockchain/best_block.rs create mode 100644 ethcore/src/blockchain/block_info.rs rename ethcore/src/{ => blockchain}/blockchain.rs (87%) create mode 100644 ethcore/src/blockchain/bloom_indexer.rs create mode 100644 ethcore/src/blockchain/cache.rs create mode 100644 ethcore/src/blockchain/mod.rs create mode 100644 ethcore/src/blockchain/tree_route.rs diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs new file mode 100644 index 000000000..8c7fac220 --- /dev/null +++ b/ethcore/src/blockchain/best_block.rs @@ -0,0 +1,23 @@ +use util::hash::H256; +use util::uint::U256; +use header::BlockNumber; + +/// Information about best block gathered together +#[derive(Default)] +pub struct BestBlock { + pub hash: H256, + pub number: BlockNumber, + pub total_difficulty: U256 +} + +impl BestBlock { + pub fn new() -> BestBlock { Default::default() } +} + + //BestBlock { + //hash: H256::new(), + //number: 0, + //total_difficulty: U256::from(0) + //} + //} +//} diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs new file mode 100644 index 000000000..c02fadbde --- /dev/null +++ b/ethcore/src/blockchain/block_info.rs @@ -0,0 +1,19 @@ +use util::hash::H256; +use util::uint::U256; +use header::BlockNumber; + +pub struct BlockInfo { + pub hash: H256, + pub number: BlockNumber, + pub total_difficulty: U256, + pub location: BlockLocation +} + +pub enum BlockLocation { + CanonChain, + Branch, + BranchBecomingCanonChain { + ancestor: H256, + route: Vec + } +} diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain/blockchain.rs similarity index 87% rename from ethcore/src/blockchain.rs rename to ethcore/src/blockchain/blockchain.rs index 7e878b81e..fa71bc817 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -23,113 +23,33 @@ use transaction::*; use views::*; use receipt::Receipt; use chainfilter::{ChainFilter, BloomIndex, FilterDataSource}; +use blockchain::block_info::{BlockInfo, BlockLocation}; +use blockchain::best_block::BestBlock; +use blockchain::bloom_indexer::BloomIndexer; +use blockchain::tree_route::TreeRoute; +use blockchain::CacheSize; const BLOOM_INDEX_SIZE: usize = 16; const BLOOM_LEVELS: u8 = 3; -/// Represents a tree route between `from` block and `to` block: -pub struct TreeRoute { - /// A vector of hashes of all blocks, ordered from `from` to `to`. - pub blocks: Vec, - /// Best common ancestor of these blocks. - pub ancestor: H256, - /// An index where best common ancestor would be. - pub index: usize, -} - -/// Represents blockchain's in-memory cache size in bytes. -#[derive(Debug)] -pub struct CacheSize { - /// Blocks cache size. - pub blocks: usize, - /// BlockDetails cache size. - pub block_details: usize, - /// Transaction addresses cache size. - pub transaction_addresses: usize, - /// Logs cache size. - pub block_logs: usize, - /// Blooms cache size. - pub blocks_blooms: usize, - /// Block receipts size. - pub block_receipts: usize, -} - -struct BloomIndexer { - index_size: usize, - levels: u8, -} - -impl BloomIndexer { - fn new(index_size: usize, levels: u8) -> Self { - BloomIndexer { - index_size: index_size, - levels: levels - } - } - - /// Calculates bloom's position in database. - fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { - use std::{mem, ptr}; - - let hash = unsafe { - let mut hash: H256 = mem::zeroed(); - ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); - hash[8] = bloom_index.level; - hash.reverse(); - hash - }; - - BlocksBloomLocation { - hash: hash, - index: bloom_index.index % self.index_size - } - } - - fn index_size(&self) -> usize { - self.index_size - } - - fn levels(&self) -> u8 { - self.levels - } -} - /// Blockchain update info. struct ExtrasUpdate { - /// Block hash. - hash: H256, + /// Block info. + info: BlockInfo, /// DB update batch. batch: DBTransaction, - /// Inserted block familial details. - details: BlockDetails, - /// New best block (if it has changed). - new_best: Option, + /// Numbers of blocks to update in block hashes cache. + block_numbers: HashSet, + /// Hashes of blocks to update in block details cache. + block_details_hashes: HashSet, + /// Hashes of receipts to update in block receipts cache. + block_receipts_hashes: HashSet, + /// Hashes of transactions to update in transactions addresses cache. + transactions_addresses_hashes: HashSet, /// Changed blocks bloom location hashes. bloom_hashes: HashSet, } -impl CacheSize { - /// Total amount used by the cache. - fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms } -} - -/// Information about best block gathered together -struct BestBlock { - pub hash: H256, - pub number: BlockNumber, - pub total_difficulty: U256 -} - -impl BestBlock { - fn new() -> BestBlock { - BestBlock { - hash: H256::new(), - number: 0, - total_difficulty: U256::from(0) - } - } -} - /// Interface for querying blocks by hash and by number. pub trait BlockProvider { /// Returns true if the given block is known @@ -452,28 +372,14 @@ impl BlockChain { /// ```json /// { blocks: [B4, B3, A3, A4], ancestor: A2, index: 2 } /// ``` - pub fn tree_route(&self, from: H256, to: H256) -> Option { - let from_details = match self.block_details(&from) { - Some(h) => h, - None => return None, - }; - let to_details = match self.block_details(&to) { - Some(h) => h, - None => return None, - }; - Some(self.tree_route_aux((&from_details, &from), (&to_details, &to))) - } - - /// Similar to `tree_route` function, but can be used to return a route - /// between blocks which may not be in database yet. - fn tree_route_aux(&self, from: (&BlockDetails, &H256), to: (&BlockDetails, &H256)) -> TreeRoute { + pub fn tree_route(&self, from: H256, to: H256) -> TreeRoute { let mut from_branch = vec![]; let mut to_branch = vec![]; - let mut from_details = from.0.clone(); - let mut to_details = to.0.clone(); - let mut current_from = from.1.clone(); - let mut current_to = to.1.clone(); + let mut from_details = self.block_details(&from).expect(&format!("Expected to find details for block {:?}", from)); + let mut to_details = self.block_details(&to).expect(&format!("Expected to find details for block {:?}", to)); + let mut current_from = from; + let mut current_to = to; // reset from && to to the same level while from_details.number > to_details.number { @@ -527,165 +433,231 @@ impl BlockChain { // store block in db self.blocks_db.put(&hash, &bytes).unwrap(); - let update = self.block_to_extras_update(bytes, receipts); - self.apply_update(update); + + let batch = DBTransaction::new(); + let info = self.block_info(bytes); + batch.put(b"best", &info.hash).unwrap(); + + self.apply_update(ExtrasUpdate { + block_numbers: self.prepare_block_hashes_update(bytes, &info, &batch), + block_details_hashes: self.prepare_block_details_update(bytes, &info, &batch), + block_receipts_hashes: self.prepare_block_receipts_update(receipts, &info, &batch), + transactions_addresses_hashes: self.prepare_transaction_addresses_update(bytes, &info, &batch), + bloom_hashes: self.prepare_block_blooms_update(bytes, &info, &batch), + batch: batch, + info: info + }); } /// Applies extras update. fn apply_update(&self, update: ExtrasUpdate) { // update best block let mut best_block = self.best_block.write().unwrap(); - if let Some(b) = update.new_best { - *best_block = b; + match update.info.location { + BlockLocation::Branch => (), + _ => { + *best_block = BestBlock { + hash: update.info.hash, + number: update.info.number, + total_difficulty: update.info.total_difficulty + }; + } } - // update details cache - let mut write_details = self.block_details.write().unwrap(); - write_details.remove(&update.details.parent); - write_details.insert(update.hash.clone(), update.details); - self.note_used(CacheID::Block(update.hash)); + let mut write_hashes = self.block_hashes.write().unwrap(); + for number in &update.block_numbers { + write_hashes.remove(number); + } + + let mut write_details = self.block_details.write().unwrap(); + for hash in &update.block_details_hashes { + write_details.remove(hash); + } + + let mut write_receipts = self.block_receipts.write().unwrap(); + for hash in &update.block_receipts_hashes { + write_receipts.remove(hash); + } + + let mut write_txs = self.transaction_addresses.write().unwrap(); + for hash in &update.transactions_addresses_hashes { + write_txs.remove(hash); + } - // update blocks blooms cache let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); for bloom_hash in &update.bloom_hashes { write_blocks_blooms.remove(bloom_hash); } - // update extras database + //// update extras database self.extras_db.write(update.batch).unwrap(); } - /// Transforms block into WriteBatch that may be written into database - /// Additionally, if it's new best block it returns new best block object. - fn block_to_extras_update(&self, bytes: &[u8], receipts: Vec) -> ExtrasUpdate { - // create views onto rlp - let block = BlockView::new(bytes); + /// Get inserted block info which is critical to preapre extras updates. + fn block_info(&self, block_bytes: &[u8]) -> BlockInfo { + let block = BlockView::new(block_bytes); let header = block.header_view(); - - // prepare variables let hash = block.sha3(); - let mut parent_details = self.block_details(&header.parent_hash()).expect(format!("Invalid parent hash: {:?}", header.parent_hash()).as_ref()); + let number = header.number(); + let parent_hash = header.parent_hash(); + let parent_details = self.block_details(&parent_hash).expect(format!("Invalid parent hash: {:?}", parent_hash).as_ref()); let total_difficulty = parent_details.total_difficulty + header.difficulty(); let is_new_best = total_difficulty > self.best_block_total_difficulty(); + + BlockInfo { + hash: hash, + number: number, + total_difficulty: total_difficulty, + location: match is_new_best { + false => BlockLocation::Branch, + true => { + // on new best block we need to make sure that all ancestors + // are moved to "canon chain" + // find the route between old best block and the new one + let best_hash = self.best_block_hash(); + let route = self.tree_route(best_hash, parent_hash); + + assert_eq!(number, parent_details.number + 1); + + match route.blocks.len() { + 0 => BlockLocation::CanonChain, + _ => BlockLocation::BranchBecomingCanonChain { + ancestor: route.ancestor, + route: route.blocks.into_iter().skip(route.index).collect() + } + } + } + } + } + } + + /// This function updates block number to block hash mappings and writes them to db batch. + /// + /// Returns modified block numbers. + fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + let block = BlockView::new(block_bytes); + let header = block.header_view(); + let number = header.number(); + + match info.location { + BlockLocation::Branch => vec![], + BlockLocation::CanonChain => { + batch.put_extras(&number, &info.hash); + vec![number] + }, + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => { + let ancestor_number = self.block_number(ancestor).unwrap(); + let start_number = ancestor_number + 1; + + for (index, hash) in route.iter().enumerate() { + batch.put_extras(&(start_number + index as BlockNumber), hash); + } + + batch.put_extras(&number, &info.hash); + let mut numbers: Vec = (start_number..start_number + route.len() as BlockNumber).into_iter().collect(); + numbers.push(number); + numbers + } + }.into_iter().collect() + } + + /// This function creates current block details, updates parent block details and writes them to db batch. + /// + /// Returns hashes of modified block details. + fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + let block = BlockView::new(block_bytes); + let header = block.header_view(); let parent_hash = header.parent_hash(); + // update parent + let mut parent_details = self.block_details(&parent_hash).expect(format!("Invalid parent hash: {:?}", parent_hash).as_ref()); + parent_details.children.push(info.hash.clone()); + // create current block details let details = BlockDetails { number: header.number(), - total_difficulty: total_difficulty, + total_difficulty: info.total_difficulty, parent: parent_hash.clone(), children: vec![] }; - // prepare the batch - let batch = DBTransaction::new(); - - // insert new block details - batch.put_extras(&hash, &details); - - // update parent details - parent_details.children.push(hash.clone()); + // write to batch batch.put_extras(&parent_hash, &parent_details); + batch.put_extras(&info.hash, &details); + vec![parent_hash, info.hash.clone()].into_iter().collect() + } + + /// This function writes block receipts to db batch and returns hashes of modified receipts. + fn prepare_block_receipts_update(&self, receipts: Vec, info: &BlockInfo, batch: &DBTransaction) -> HashSet { + batch.put_extras(&info.hash, &BlockReceipts::new(receipts)); + vec![info.hash.clone()].into_iter().collect() + } + + /// This function writes mapping from transaction hash to transaction address to database. + /// + /// Returns hashes of modified mappings. + fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + let block = BlockView::new(block_bytes); + let transaction_hashes = block.transaction_hashes(); // update transaction addresses - for (i, tx_hash) in block.transaction_hashes().iter().enumerate() { + for (i, tx_hash) in transaction_hashes.iter().enumerate() { batch.put_extras(tx_hash, &TransactionAddress { - block_hash: hash.clone(), + block_hash: info.hash.clone(), index: i }); } - // update block receipts - batch.put_extras(&hash, &BlockReceipts::new(receipts)); + transaction_hashes.into_iter().collect() + } - // if it's not new best block, just return - if !is_new_best { - return ExtrasUpdate { - hash: hash.clone(), - batch: batch, - details: details, - new_best: None, - bloom_hashes: HashSet::new() - }; - } + /// This functions update blcoks blooms and writes them to db batch. + /// + /// TODO: this function needs comprehensive description. + fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + let block = BlockView::new(block_bytes); + let header = block.header_view(); - // if its new best block we need to make sure that all ancestors - // are moved to "canon chain" - // find the route between old best block and the new one - let best_hash = self.best_block_hash(); - let best_details = self.block_details(&best_hash).expect("best block hash is invalid!"); - let route = self.tree_route_aux((&best_details, &best_hash), (&details, &hash)); - - let modified_blooms; - - match route.blocks.len() { - // its our parent - 1 => { - batch.put_extras(&header.number(), &hash); - - // update block blooms - modified_blooms = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) - .add_bloom(&header.log_bloom(), header.number() as usize); + let modified_blooms = match info.location { + BlockLocation::Branch => HashMap::new(), + BlockLocation::CanonChain => { + ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) + .add_bloom(&header.log_bloom(), header.number() as usize) }, - // it is a fork - i if i > 1 => { - let ancestor_number = self.block_number(&route.ancestor).unwrap(); + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => { + let ancestor_number = self.block_number(ancestor).unwrap(); let start_number = ancestor_number + 1; - for (index, hash) in route.blocks.iter().skip(route.index).enumerate() { - batch.put_extras(&(start_number + index as BlockNumber), hash); - } - // get all blocks that are not part of canon chain (TODO: optimize it to one query) - let blooms: Vec = route.blocks.iter() - .skip(route.index) + let mut blooms: Vec = route.iter() .map(|hash| self.block(hash).unwrap()) .map(|bytes| BlockView::new(&bytes).header_view().log_bloom()) .collect(); - // reset blooms chain head - modified_blooms = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) - .reset_chain_head(&blooms, start_number as usize, self.best_block_number() as usize); - }, - // route.blocks.len() could be 0 only if inserted block is best block, - // and this is not possible at this stage - _ => { unreachable!(); } + blooms.push(header.log_bloom()); + + ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) + .reset_chain_head(&blooms, start_number as usize, self.best_block_number() as usize) + } }; - let bloom_hashes = modified_blooms.iter() - .map(|(bloom_index, _)| self.bloom_indexer.location(&bloom_index).hash) - .collect(); - - for (bloom_hash, blocks_blooms) in modified_blooms.into_iter() + let indexed_blocks_blooms = modified_blooms.into_iter() .fold(HashMap::new(), | mut acc, (bloom_index, bloom) | { { let location = self.bloom_indexer.location(&bloom_index); let mut blocks_blooms = acc .entry(location.hash.clone()) .or_insert_with(|| self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new)); - assert_eq!(self.bloom_indexer.index_size, blocks_blooms.blooms.len()); + assert_eq!(self.bloom_indexer.index_size(), blocks_blooms.blooms.len()); blocks_blooms.blooms[location.index] = bloom; } acc - }) { - batch.put_extras(&bloom_hash, &blocks_blooms); + }); + + for (bloom_hash, blocks_blooms) in &indexed_blocks_blooms { + batch.put_extras(bloom_hash, blocks_blooms); } - // this is new best block - batch.put(b"best", &hash).unwrap(); - - let best_block = BestBlock { - hash: hash.clone(), - number: header.number(), - total_difficulty: total_difficulty - }; - - ExtrasUpdate { - hash: hash, - batch: batch, - new_best: Some(best_block), - details: details, - bloom_hashes: bloom_hashes - } + indexed_blocks_blooms.into_iter().map(|(bloom_hash, _)| bloom_hash).collect() } /// Get best block hash. @@ -886,52 +858,52 @@ mod tests { assert_eq!(bc.block_hash(3).unwrap(), b3a_hash); // test trie route - let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone()).unwrap(); + let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone()); assert_eq!(r0_1.ancestor, genesis_hash); assert_eq!(r0_1.blocks, [b1_hash.clone()]); assert_eq!(r0_1.index, 0); - let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone()).unwrap(); + let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone()); assert_eq!(r0_2.ancestor, genesis_hash); assert_eq!(r0_2.blocks, [b1_hash.clone(), b2_hash.clone()]); assert_eq!(r0_2.index, 0); - let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone()).unwrap(); + let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone()); assert_eq!(r1_3a.ancestor, b1_hash); assert_eq!(r1_3a.blocks, [b2_hash.clone(), b3a_hash.clone()]); assert_eq!(r1_3a.index, 0); - let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone()).unwrap(); + let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone()); assert_eq!(r1_3b.ancestor, b1_hash); assert_eq!(r1_3b.blocks, [b2_hash.clone(), b3b_hash.clone()]); assert_eq!(r1_3b.index, 0); - let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone()).unwrap(); + let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone()); assert_eq!(r3a_3b.ancestor, b2_hash); assert_eq!(r3a_3b.blocks, [b3a_hash.clone(), b3b_hash.clone()]); assert_eq!(r3a_3b.index, 1); - let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone()).unwrap(); + let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone()); assert_eq!(r1_0.ancestor, genesis_hash); assert_eq!(r1_0.blocks, [b1_hash.clone()]); assert_eq!(r1_0.index, 1); - let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone()).unwrap(); + let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone()); assert_eq!(r2_0.ancestor, genesis_hash); assert_eq!(r2_0.blocks, [b2_hash.clone(), b1_hash.clone()]); assert_eq!(r2_0.index, 2); - let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone()).unwrap(); + let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone()); assert_eq!(r3a_1.ancestor, b1_hash); assert_eq!(r3a_1.blocks, [b3a_hash.clone(), b2_hash.clone()]); assert_eq!(r3a_1.index, 2); - let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone()).unwrap(); + let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone()); assert_eq!(r3b_1.ancestor, b1_hash); assert_eq!(r3b_1.blocks, [b3b_hash.clone(), b2_hash.clone()]); assert_eq!(r3b_1.index, 2); - let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone()).unwrap(); + let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone()); assert_eq!(r3b_3a.ancestor, b2_hash); assert_eq!(r3b_3a.blocks, [b3b_hash.clone(), b3a_hash.clone()]); assert_eq!(r3b_3a.index, 1); @@ -1092,7 +1064,7 @@ mod tests { #[test] fn test_bloom_indexer() { use chainfilter::BloomIndex; - use blockchain::BloomIndexer; + use blockchain::bloom_indexer::BloomIndexer; use extras::BlocksBloomLocation; let bi = BloomIndexer::new(16, 3); diff --git a/ethcore/src/blockchain/bloom_indexer.rs b/ethcore/src/blockchain/bloom_indexer.rs new file mode 100644 index 000000000..83c15992f --- /dev/null +++ b/ethcore/src/blockchain/bloom_indexer.rs @@ -0,0 +1,43 @@ +use util::hash::H256; +use chainfilter::BloomIndex; +use extras::BlocksBloomLocation; + +pub struct BloomIndexer { + index_size: usize, + levels: u8, +} + +impl BloomIndexer { + pub fn new(index_size: usize, levels: u8) -> Self { + BloomIndexer { + index_size: index_size, + levels: levels + } + } + + /// Calculates bloom's position in database. + pub fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { + use std::{mem, ptr}; + + let hash = unsafe { + let mut hash: H256 = mem::zeroed(); + ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); + hash[8] = bloom_index.level; + hash.reverse(); + hash + }; + + BlocksBloomLocation { + hash: hash, + index: bloom_index.index % self.index_size + } + } + + pub fn index_size(&self) -> usize { + self.index_size + } + + pub fn levels(&self) -> u8 { + self.levels + } +} diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs new file mode 100644 index 000000000..c9536bdb4 --- /dev/null +++ b/ethcore/src/blockchain/cache.rs @@ -0,0 +1,23 @@ + + +/// Represents blockchain's in-memory cache size in bytes. +#[derive(Debug)] +pub struct CacheSize { + /// Blocks cache size. + pub blocks: usize, + /// BlockDetails cache size. + pub block_details: usize, + /// Transaction addresses cache size. + pub transaction_addresses: usize, + /// Logs cache size. + pub block_logs: usize, + /// Blooms cache size. + pub blocks_blooms: usize, + /// Block receipts size. + pub block_receipts: usize, +} + +impl CacheSize { + /// Total amount used by the cache. + pub fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms } +} diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs new file mode 100644 index 000000000..697c5375b --- /dev/null +++ b/ethcore/src/blockchain/mod.rs @@ -0,0 +1,10 @@ +pub mod blockchain; +mod best_block; +mod block_info; +mod bloom_indexer; +mod cache; +mod tree_route; + +pub use self::blockchain::{BlockProvider, BlockChain}; +pub use self::cache::CacheSize; +pub use self::tree_route::TreeRoute; diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/blockchain/tree_route.rs new file mode 100644 index 000000000..b7a230b34 --- /dev/null +++ b/ethcore/src/blockchain/tree_route.rs @@ -0,0 +1,13 @@ +use util::hash::H256; + +/// Represents a tree route between `from` block and `to` block: +#[derive(Debug)] +pub struct TreeRoute { + /// A vector of hashes of all blocks, ordered from `from` to `to`. + pub blocks: Vec, + /// Best common ancestor of these blocks. + pub ancestor: H256, + /// An index where best common ancestor would be. + pub index: usize, +} + diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index b2ac2b9e1..33365b63c 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -408,7 +408,11 @@ impl BlockChainClient for Client { } fn tree_route(&self, from: &H256, to: &H256) -> Option { - self.chain.read().unwrap().tree_route(from.clone(), to.clone()) + let chain = self.chain.read().unwrap(); + match chain.is_known(from) && chain.is_known(to) { + true => Some(chain.tree_route(from.clone(), to.clone())), + false => None + } } fn state_data(&self, _hash: &H256) -> Option { From cd43e32e25d9809b8ceb19b0bf5b8735f3e8294a Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 02:16:39 +0100 Subject: [PATCH 241/753] added docs and license headers --- ethcore/src/blockchain/best_block.rs | 33 +++++++------ ethcore/src/blockchain/block_info.rs | 29 ++++++++++++ ethcore/src/blockchain/blockchain.rs | 58 ++++------------------- ethcore/src/blockchain/bloom_indexer.rs | 61 ++++++++++++++++++++++++- ethcore/src/blockchain/cache.rs | 14 ++++++ ethcore/src/blockchain/mod.rs | 19 ++++++++ ethcore/src/blockchain/tree_route.rs | 16 +++++++ ethcore/src/blockchain/update.rs | 23 ++++++++++ ethcore/src/extras.rs | 9 ---- 9 files changed, 189 insertions(+), 73 deletions(-) create mode 100644 ethcore/src/blockchain/update.rs diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index 8c7fac220..cbb219617 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -1,23 +1,30 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + use util::hash::H256; use util::uint::U256; use header::BlockNumber; -/// Information about best block gathered together +/// Best block info. #[derive(Default)] pub struct BestBlock { + /// Best block hash. pub hash: H256, + /// Best block number. pub number: BlockNumber, + /// Best block total difficulty. pub total_difficulty: U256 } - -impl BestBlock { - pub fn new() -> BestBlock { Default::default() } -} - - //BestBlock { - //hash: H256::new(), - //number: 0, - //total_difficulty: U256::from(0) - //} - //} -//} diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index c02fadbde..98dac648d 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -1,19 +1,48 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + use util::hash::H256; use util::uint::U256; use header::BlockNumber; +/// Brief info about inserted block. pub struct BlockInfo { + /// Block hash. pub hash: H256, + /// Block number. pub number: BlockNumber, + /// Total block difficulty. pub total_difficulty: U256, + /// Block location in blockchain. pub location: BlockLocation } +/// Describes location of newly inserted block. pub enum BlockLocation { + /// It's part of the canon chain. CanonChain, + /// It's not a part of the canon chain. Branch, + /// It's part of the fork which should become canon chain, + /// because it's total difficulty is higher than current + /// canon chain difficulty. BranchBecomingCanonChain { + /// Hash of the newest common ancestor with old canon chain. ancestor: H256, + /// Hashes of the blocks between ancestor and this block. route: Vec } } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index fa71bc817..36755c891 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -27,29 +27,12 @@ use blockchain::block_info::{BlockInfo, BlockLocation}; use blockchain::best_block::BestBlock; use blockchain::bloom_indexer::BloomIndexer; use blockchain::tree_route::TreeRoute; +use blockchain::update::ExtrasUpdate; use blockchain::CacheSize; const BLOOM_INDEX_SIZE: usize = 16; const BLOOM_LEVELS: u8 = 3; -/// Blockchain update info. -struct ExtrasUpdate { - /// Block info. - info: BlockInfo, - /// DB update batch. - batch: DBTransaction, - /// Numbers of blocks to update in block hashes cache. - block_numbers: HashSet, - /// Hashes of blocks to update in block details cache. - block_details_hashes: HashSet, - /// Hashes of receipts to update in block receipts cache. - block_receipts_hashes: HashSet, - /// Hashes of transactions to update in transactions addresses cache. - transactions_addresses_hashes: HashSet, - /// Changed blocks bloom location hashes. - bloom_hashes: HashSet, -} - /// Interface for querying blocks by hash and by number. pub trait BlockProvider { /// Returns true if the given block is known @@ -271,7 +254,7 @@ impl BlockChain { let bc = BlockChain { pref_cache_size: 1 << 14, max_cache_size: 1 << 20, - best_block: RwLock::new(BestBlock::new()), + best_block: RwLock::new(BestBlock::default()), blocks: RwLock::new(HashMap::new()), block_details: RwLock::new(HashMap::new()), block_hashes: RwLock::new(HashMap::new()), @@ -376,8 +359,8 @@ impl BlockChain { let mut from_branch = vec![]; let mut to_branch = vec![]; - let mut from_details = self.block_details(&from).expect(&format!("Expected to find details for block {:?}", from)); - let mut to_details = self.block_details(&to).expect(&format!("Expected to find details for block {:?}", to)); + let mut from_details = self.block_details(&from).expect(&format!("0. Expected to find details for block {:?}", from)); + let mut to_details = self.block_details(&to).expect(&format!("1. Expected to find details for block {:?}", to)); let mut current_from = from; let mut current_to = to; @@ -385,13 +368,13 @@ impl BlockChain { while from_details.number > to_details.number { from_branch.push(current_from); current_from = from_details.parent.clone(); - from_details = self.block_details(&from_details.parent).expect(&format!("1. Expected to find details for block {:?}", from_details.parent)); + from_details = self.block_details(&from_details.parent).expect(&format!("2. Expected to find details for block {:?}", from_details.parent)); } while to_details.number > from_details.number { to_branch.push(current_to); current_to = to_details.parent.clone(); - to_details = self.block_details(&to_details.parent).expect(&format!("2. Expected to find details for block {:?}", to_details.parent)); + to_details = self.block_details(&to_details.parent).expect(&format!("3. Expected to find details for block {:?}", to_details.parent)); } assert_eq!(from_details.number, to_details.number); @@ -400,11 +383,11 @@ impl BlockChain { while current_from != current_to { from_branch.push(current_from); current_from = from_details.parent.clone(); - from_details = self.block_details(&from_details.parent).expect(&format!("3. Expected to find details for block {:?}", from_details.parent)); + from_details = self.block_details(&from_details.parent).expect(&format!("4. Expected to find details for block {:?}", from_details.parent)); to_branch.push(current_to); current_to = to_details.parent.clone(); - to_details = self.block_details(&to_details.parent).expect(&format!("4. Expected to find details for block {:?}", from_details.parent)); + to_details = self.block_details(&to_details.parent).expect(&format!("5. Expected to find details for block {:?}", from_details.parent)); } let index = from_branch.len(); @@ -1061,30 +1044,5 @@ mod tests { assert_eq!(blocks_ba, vec![3]); } - #[test] - fn test_bloom_indexer() { - use chainfilter::BloomIndex; - use blockchain::bloom_indexer::BloomIndexer; - use extras::BlocksBloomLocation; - let bi = BloomIndexer::new(16, 3); - - let index = BloomIndex::new(0, 0); - assert_eq!(bi.location(&index), BlocksBloomLocation { - hash: H256::new(), - index: 0 - }); - - let index = BloomIndex::new(1, 0); - assert_eq!(bi.location(&index), BlocksBloomLocation { - hash: H256::from_str("0000000000000000000000000000000000000000000000010000000000000000").unwrap(), - index: 0 - }); - - let index = BloomIndex::new(0, 299_999); - assert_eq!(bi.location(&index), BlocksBloomLocation { - hash: H256::from_str("000000000000000000000000000000000000000000000000000000000000493d").unwrap(), - index: 15 - }); - } } diff --git a/ethcore/src/blockchain/bloom_indexer.rs b/ethcore/src/blockchain/bloom_indexer.rs index 83c15992f..74c679ba8 100644 --- a/ethcore/src/blockchain/bloom_indexer.rs +++ b/ethcore/src/blockchain/bloom_indexer.rs @@ -1,13 +1,39 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + use util::hash::H256; use chainfilter::BloomIndex; -use extras::BlocksBloomLocation; +/// Represents location of block bloom in extras database. +#[derive(Debug, PartialEq)] +pub struct BlocksBloomLocation { + /// Unique hash of BlocksBloom + pub hash: H256, + /// Index within BlocksBloom + pub index: usize, +} + +/// Should be used to localize blocks blooms in extras database. pub struct BloomIndexer { index_size: usize, levels: u8, } impl BloomIndexer { + /// Plain constructor. pub fn new(index_size: usize, levels: u8) -> Self { BloomIndexer { index_size: index_size, @@ -33,11 +59,44 @@ impl BloomIndexer { } } + /// Returns index size. pub fn index_size(&self) -> usize { self.index_size } + /// Returns number of cache levels. pub fn levels(&self) -> u8 { self.levels } } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use util::hash::{H256, FixedHash}; + use chainfilter::BloomIndex; + use blockchain::bloom_indexer::{BloomIndexer, BlocksBloomLocation}; + + #[test] + fn test_bloom_indexer() { + let bi = BloomIndexer::new(16, 3); + + let index = BloomIndex::new(0, 0); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::new(), + index: 0 + }); + + let index = BloomIndex::new(1, 0); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::from_str("0000000000000000000000000000000000000000000000010000000000000000").unwrap(), + index: 0 + }); + + let index = BloomIndex::new(0, 299_999); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::from_str("000000000000000000000000000000000000000000000000000000000000493d").unwrap(), + index: 15 + }); + } +} diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs index c9536bdb4..722f83c16 100644 --- a/ethcore/src/blockchain/cache.rs +++ b/ethcore/src/blockchain/cache.rs @@ -1,4 +1,18 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . /// Represents blockchain's in-memory cache size in bytes. #[derive(Debug)] diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 697c5375b..43ffb9818 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -1,9 +1,28 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain database. + pub mod blockchain; mod best_block; mod block_info; mod bloom_indexer; mod cache; mod tree_route; +mod update; pub use self::blockchain::{BlockProvider, BlockChain}; pub use self::cache::CacheSize; diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/blockchain/tree_route.rs index b7a230b34..1bd0e6f75 100644 --- a/ethcore/src/blockchain/tree_route.rs +++ b/ethcore/src/blockchain/tree_route.rs @@ -1,3 +1,19 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + use util::hash::H256; /// Represents a tree route between `from` block and `to` block: diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs new file mode 100644 index 000000000..083bcbf4e --- /dev/null +++ b/ethcore/src/blockchain/update.rs @@ -0,0 +1,23 @@ +use std::collections::HashSet; +use util::hash::H256; +use util::kvdb::DBTransaction; +use header::BlockNumber; +use blockchain::block_info::BlockInfo; + +/// Block extras update info. +pub struct ExtrasUpdate { + /// Block info. + pub info: BlockInfo, + /// DB update batch. + pub batch: DBTransaction, + /// Numbers of blocks to update in block hashes cache. + pub block_numbers: HashSet, + /// Hashes of blocks to update in block details cache. + pub block_details_hashes: HashSet, + /// Hashes of receipts to update in block receipts cache. + pub block_receipts_hashes: HashSet, + /// Hashes of transactions to update in transactions addresses cache. + pub transactions_addresses_hashes: HashSet, + /// Changed blocks bloom location hashes. + pub bloom_hashes: HashSet, +} diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index 128357576..f4759b040 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -262,15 +262,6 @@ impl Encodable for BlocksBlooms { } } -/// Represents location of bloom in database. -#[derive(Debug, PartialEq)] -pub struct BlocksBloomLocation { - /// Unique hash of BlocksBloom - pub hash: H256, - /// Index within BlocksBloom - pub index: usize, -} - /// Represents address of certain transaction within block #[derive(Clone)] pub struct TransactionAddress { From 01f69ca80c85348070fffa5a1a108d83edc0d0fa Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 10:19:33 +0100 Subject: [PATCH 242/753] moved creation of blockchains db transaction to apply_update function --- ethcore/src/blockchain/blockchain.rs | 122 +++++++++++++-------------- ethcore/src/blockchain/update.rs | 16 ++-- 2 files changed, 65 insertions(+), 73 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 36755c891..6a8e1258d 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -417,23 +417,23 @@ impl BlockChain { // store block in db self.blocks_db.put(&hash, &bytes).unwrap(); - let batch = DBTransaction::new(); let info = self.block_info(bytes); - batch.put(b"best", &info.hash).unwrap(); self.apply_update(ExtrasUpdate { - block_numbers: self.prepare_block_hashes_update(bytes, &info, &batch), - block_details_hashes: self.prepare_block_details_update(bytes, &info, &batch), - block_receipts_hashes: self.prepare_block_receipts_update(receipts, &info, &batch), - transactions_addresses_hashes: self.prepare_transaction_addresses_update(bytes, &info, &batch), - bloom_hashes: self.prepare_block_blooms_update(bytes, &info, &batch), - batch: batch, + block_hashes: self.prepare_block_hashes_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info), + block_receipts: self.prepare_block_receipts_update(receipts, &info), + transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(bytes, &info), info: info }); } /// Applies extras update. fn apply_update(&self, update: ExtrasUpdate) { + let batch = DBTransaction::new(); + batch.put(b"best", &update.info.hash).unwrap(); + // update best block let mut best_block = self.best_block.write().unwrap(); match update.info.location { @@ -448,32 +448,37 @@ impl BlockChain { } let mut write_hashes = self.block_hashes.write().unwrap(); - for number in &update.block_numbers { + for (number, hash) in &update.block_hashes { + batch.put_extras(number, hash); write_hashes.remove(number); } let mut write_details = self.block_details.write().unwrap(); - for hash in &update.block_details_hashes { - write_details.remove(hash); + for (hash, details) in update.block_details.into_iter() { + batch.put_extras(&hash, &details); + write_details.insert(hash, details); } let mut write_receipts = self.block_receipts.write().unwrap(); - for hash in &update.block_receipts_hashes { + for (hash, receipt) in &update.block_receipts { + batch.put_extras(hash, receipt); write_receipts.remove(hash); } let mut write_txs = self.transaction_addresses.write().unwrap(); - for hash in &update.transactions_addresses_hashes { + for (hash, tx_address) in &update.transactions_addresses { + batch.put_extras(hash, tx_address); write_txs.remove(hash); } let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); - for bloom_hash in &update.bloom_hashes { + for (bloom_hash, blocks_bloom) in &update.blocks_blooms { + batch.put_extras(bloom_hash, blocks_bloom); write_blocks_blooms.remove(bloom_hash); } - //// update extras database - self.extras_db.write(update.batch).unwrap(); + // update extras database + self.extras_db.write(batch).unwrap(); } /// Get inserted block info which is critical to preapre extras updates. @@ -514,40 +519,35 @@ impl BlockChain { } } - /// This function updates block number to block hash mappings and writes them to db batch. - /// - /// Returns modified block numbers. - fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + /// This function returns modified block hashes. + fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + let mut block_hashes = HashMap::new(); let block = BlockView::new(block_bytes); let header = block.header_view(); let number = header.number(); match info.location { - BlockLocation::Branch => vec![], + BlockLocation::Branch => (), BlockLocation::CanonChain => { - batch.put_extras(&number, &info.hash); - vec![number] + block_hashes.insert(number, info.hash.clone()); }, BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => { let ancestor_number = self.block_number(ancestor).unwrap(); let start_number = ancestor_number + 1; - for (index, hash) in route.iter().enumerate() { - batch.put_extras(&(start_number + index as BlockNumber), hash); + for (index, hash) in route.iter().cloned().enumerate() { + block_hashes.insert(start_number + index as BlockNumber, hash); } - batch.put_extras(&number, &info.hash); - let mut numbers: Vec = (start_number..start_number + route.len() as BlockNumber).into_iter().collect(); - numbers.push(number); - numbers + block_hashes.insert(number, info.hash.clone()); } - }.into_iter().collect() + } + + block_hashes } - /// This function creates current block details, updates parent block details and writes them to db batch. - /// - /// Returns hashes of modified block details. - fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + /// This function returns modified block details. + fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); @@ -565,39 +565,39 @@ impl BlockChain { }; // write to batch - batch.put_extras(&parent_hash, &parent_details); - batch.put_extras(&info.hash, &details); - vec![parent_hash, info.hash.clone()].into_iter().collect() + let mut block_details = HashMap::new(); + block_details.insert(parent_hash, parent_details); + block_details.insert(info.hash.clone(), details); + block_details } - /// This function writes block receipts to db batch and returns hashes of modified receipts. - fn prepare_block_receipts_update(&self, receipts: Vec, info: &BlockInfo, batch: &DBTransaction) -> HashSet { - batch.put_extras(&info.hash, &BlockReceipts::new(receipts)); - vec![info.hash.clone()].into_iter().collect() + /// This function returns modified block receipts. + fn prepare_block_receipts_update(&self, receipts: Vec, info: &BlockInfo) -> HashMap { + let mut block_receipts = HashMap::new(); + block_receipts.insert(info.hash.clone(), BlockReceipts::new(receipts)); + block_receipts } - /// This function writes mapping from transaction hash to transaction address to database. - /// - /// Returns hashes of modified mappings. - fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + /// This function returns modified transaction addresses. + fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); let transaction_hashes = block.transaction_hashes(); - // update transaction addresses - for (i, tx_hash) in transaction_hashes.iter().enumerate() { - batch.put_extras(tx_hash, &TransactionAddress { - block_hash: info.hash.clone(), - index: i - }); - } - - transaction_hashes.into_iter().collect() + transaction_hashes.into_iter() + .enumerate() + .fold(HashMap::new(), |mut acc, (i ,tx_hash)| { + acc.insert(tx_hash, TransactionAddress { + block_hash: info.hash.clone(), + index: i + }); + acc + }) } - /// This functions update blcoks blooms and writes them to db batch. + /// This functions returns modified blocks blooms. /// /// TODO: this function needs comprehensive description. - fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo, batch: &DBTransaction) -> HashSet { + fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); let header = block.header_view(); @@ -623,7 +623,7 @@ impl BlockChain { } }; - let indexed_blocks_blooms = modified_blooms.into_iter() + modified_blooms.into_iter() .fold(HashMap::new(), | mut acc, (bloom_index, bloom) | { { let location = self.bloom_indexer.location(&bloom_index); @@ -634,13 +634,7 @@ impl BlockChain { blocks_blooms.blooms[location.index] = bloom; } acc - }); - - for (bloom_hash, blocks_blooms) in &indexed_blocks_blooms { - batch.put_extras(bloom_hash, blocks_blooms); - } - - indexed_blocks_blooms.into_iter().map(|(bloom_hash, _)| bloom_hash).collect() + }) } /// Get best block hash. diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 083bcbf4e..4d0fa3881 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -1,23 +1,21 @@ -use std::collections::HashSet; +use std::collections::HashMap; use util::hash::H256; -use util::kvdb::DBTransaction; use header::BlockNumber; use blockchain::block_info::BlockInfo; +use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms}; /// Block extras update info. pub struct ExtrasUpdate { /// Block info. pub info: BlockInfo, - /// DB update batch. - pub batch: DBTransaction, /// Numbers of blocks to update in block hashes cache. - pub block_numbers: HashSet, + pub block_hashes: HashMap, /// Hashes of blocks to update in block details cache. - pub block_details_hashes: HashSet, + pub block_details: HashMap, /// Hashes of receipts to update in block receipts cache. - pub block_receipts_hashes: HashSet, + pub block_receipts: HashMap, /// Hashes of transactions to update in transactions addresses cache. - pub transactions_addresses_hashes: HashSet, + pub transactions_addresses: HashMap, /// Changed blocks bloom location hashes. - pub bloom_hashes: HashSet, + pub blocks_blooms: HashMap, } From 7b3613e1f0f0fa7ba0d257b99f21436e4bda56d7 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 10:21:44 +0100 Subject: [PATCH 243/753] updated ExtrasUpdate function --- ethcore/src/blockchain/update.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 4d0fa3881..f8ca06e66 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -8,14 +8,14 @@ use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms}; pub struct ExtrasUpdate { /// Block info. pub info: BlockInfo, - /// Numbers of blocks to update in block hashes cache. + /// Modified block hashes. pub block_hashes: HashMap, - /// Hashes of blocks to update in block details cache. + /// Modified block details. pub block_details: HashMap, - /// Hashes of receipts to update in block receipts cache. + /// Modified block receipts. pub block_receipts: HashMap, - /// Hashes of transactions to update in transactions addresses cache. + /// Modified transaction addresses. pub transactions_addresses: HashMap, - /// Changed blocks bloom location hashes. + /// Modified blocks blooms. pub blocks_blooms: HashMap, } From e3c8c99583e96466b00fa51514763eb3b84add6a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 27 Feb 2016 15:02:02 +0300 Subject: [PATCH 244/753] finally caught mul bug --- util/src/uint.rs | 104 +++++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index b4940cfb8..97e7eecb3 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -173,53 +173,60 @@ macro_rules! uint_overflowing_mul { mov %rax, $0 mov %rdx, $1 - mov $6, %rax - mulq $9 + mov $5, %rax + mulq $10 add %rax, $1 + adc $$0, %rdx mov %rdx, $2 mov $5, %rax - mulq $10 - add %rax, $1 - adc %rdx, $2 - - mov $6, %rax - mulq $10 + mulq $11 add %rax, $2 + adc $$0, %rdx mov %rdx, $3 - mov $7, %rax - mulq $9 - add %rax, $2 - adc %rdx, $3 - - mov $5, %rax - mulq $11 - add %rax, $2 - adc %rdx, $3 - - mov $8, %rax - mulq $9 - adc %rax, $3 - adc $$0, %rdx - mov %rdx, %rcx - - mov $7, %rax - mulq $10 - add %rax, $3 - adc $$0, %rdx - or %rdx, %rcx - - mov $6, %rax - mulq $11 - add %rax, $3 - adc $$0, %rdx - or %rdx, %rcx - mov $5, %rax mulq $12 add %rax, $3 adc $$0, %rdx + mov %rdx, %rcx + + mov $6, %rax + mulq $9 + add %rax, $1 + adc %rdx, $2 + adc $$0, $3 + adc $$0, %rcx + + mov $6, %rax + mulq $10 + add %rax, $2 + adc %rdx, $3 + adc $$0, %rcx + adc $$0, $3 + adc $$0, %rcx + + mov $6, %rax + mulq $11 + add %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + + mov $7, %rax + mulq $9 + add %rax, $2 + adc %rdx, $3 + adc $$0, %rcx + + mov $7, %rax + mulq $10 + add %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + + mov $8, %rax + mulq $9 + add %rax, $3 or %rdx, %rcx cmpq $$0, %rcx @@ -251,15 +258,15 @@ macro_rules! uint_overflowing_mul { jrcxz 2f popcnt $7, %rcx - 2: - " + 2: + " : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), /* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow) : /* $5 */ "m"(self_t[0]), /* $6 */ "m"(self_t[1]), /* $7 */ "m"(self_t[2]), /* $8 */ "m"(self_t[3]), /* $9 */ "m"(other_t[0]), /* $10 */ "m"(other_t[1]), /* $11 */ "m"(other_t[2]), /* $12 */ "m"(other_t[3]) - : "rax", "rdx", "rbx" + : "rax", "rdx" : ); @@ -1533,6 +1540,8 @@ mod tests { #[test] fn u256_multi_muls() { + use hash::*; + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); assert_eq!(U256([0, 0, 0, 0]), result); @@ -1572,6 +1581,23 @@ mod tests { let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); assert_eq!(U256([1, 0, 0, 0]), result); + + let x1 = U256::from_str("0000000000000000000000000000000000000000000000000000012365124623").unwrap(); + let x2sqr_right = U256::from_str("000000000000000000000000000000000000000000014baeef72e0378e2328c9").unwrap(); + let x1sqr = x1 * x1; + assert_eq!(H256::from(x2sqr_right), H256::from(x1sqr)); + let x1cube = x1sqr * x1; + let x1cube_right = U256::from_str("0000000000000000000000000000000001798acde139361466f712813717897b").unwrap(); + assert_eq!(H256::from(x1cube_right), H256::from(x1cube)); + let x1quad = x1cube * x1; + let x1quad_right = U256::from_str("000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1").unwrap(); + assert_eq!(H256::from(x1quad_right), H256::from(x1quad)); + let x1penta = x1quad * x1; + let x1penta_right = U256::from_str("00000000000001e92875ac24be246e1c57e0507e8c46cc8d233b77f6f4c72993").unwrap(); + assert_eq!(H256::from(x1penta_right), H256::from(x1penta)); + let x1septima = x1penta * x1; + let x1septima_right = U256::from_str("00022cca1da3f6e5722b7d3cc5bbfb486465ebc5a708dd293042f932d7eee119").unwrap(); + assert_eq!(H256::from(x1septima_right), H256::from(x1septima)); } #[test] From 11de5b4923cced678352798f4d87841de2069e00 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 13:14:58 +0100 Subject: [PATCH 245/753] udpated serde to version 0.7.0 --- Cargo.lock | 43 ++++++++++++++++++-------------- rpc/Cargo.toml | 12 ++++----- rpc/src/lib.rs | 4 +-- rpc/src/v1/types/block_number.rs | 6 ++--- rpc/src/v1/types/bytes.rs | 2 +- rpc/src/v1/types/filter.rs | 3 ++- rpc/src/v1/types/index.rs | 6 ++--- util/Cargo.toml | 4 +-- util/src/hash.rs | 8 +++--- util/src/uint.rs | 2 +- 10 files changed, 48 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40fcb6627..7e5f209c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,15 +151,15 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.4" -source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e" +source = "git+https://github.com/ethcore/rust-secp256k1#283a0677d8327536be58a87e0494d7e0e7b1d1d8" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -205,12 +205,12 @@ dependencies = [ "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", - "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -223,7 +223,7 @@ dependencies = [ "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", + "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", "ethcore-devtools 0.9.99", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -238,7 +238,7 @@ dependencies = [ "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -371,22 +371,22 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "1.1.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-http-server" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -689,9 +689,14 @@ dependencies = [ "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde_codegen" -version = "0.6.14" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -703,11 +708,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index c91549b86..b9ca9deac 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -9,19 +9,19 @@ build = "build.rs" [lib] [dependencies] -serde = "0.6.7" -serde_json = "0.6.0" -jsonrpc-core = "1.1" -jsonrpc-http-server = "2.0" +serde = "0.7.0" +serde_json = "0.7.0" +jsonrpc-core = "1.2" +jsonrpc-http-server = "2.1" ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } clippy = { version = "0.0.44", optional = true } rustc-serialize = "0.3" -serde_macros = { version = "0.6.13", optional = true } +serde_macros = { version = "0.7.0", optional = true } [build-dependencies] -serde_codegen = { version = "0.6.13", optional = true } +serde_codegen = { version = "0.7.0", optional = true } syntex = "0.29.0" [features] diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index d7b5bdc3b..8dd58d0b8 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -16,8 +16,8 @@ //! Ethcore rpc. #![warn(missing_docs)] -#![cfg_attr(nightly, feature(custom_derive, custom_attribute, plugin))] -#![cfg_attr(nightly, plugin(serde_macros, clippy))] +#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] extern crate rustc_serialize; extern crate serde; diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index bb563de99..c955ec895 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -30,7 +30,7 @@ pub enum BlockNumber { impl Deserialize for BlockNumber { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.visit(BlockNumberVisitor) + deserializer.deserialize(BlockNumberVisitor) } } @@ -44,8 +44,8 @@ impl Visitor for BlockNumberVisitor { "latest" => Ok(BlockNumber::Latest), "earliest" => Ok(BlockNumber::Earliest), "pending" => Ok(BlockNumber::Pending), - _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")), - _ => value.parse::().map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")) + _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::custom("invalid block number")), + _ => value.parse::().map(BlockNumber::Num).map_err(|_| Error::custom("invalid block number")) } } diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index d6a648d7c..f09f24e4d 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -40,7 +40,7 @@ impl Serialize for Bytes { where S: Serializer { let mut serialized = "0x".to_owned(); serialized.push_str(self.0.to_hex().as_ref()); - serializer.visit_str(serialized.as_ref()) + serializer.serialize_str(serialized.as_ref()) } } diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index c5c3604dd..01d322cce 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -40,7 +40,7 @@ impl Deserialize for VariadicValue where T: Deserialize { Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Single) .or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Multiple)) - .map_err(|_| Error::syntax("")) // unreachable, but types must match + .map_err(|_| Error::custom("")) // unreachable, but types must match } } @@ -48,6 +48,7 @@ pub type FilterAddress = VariadicValue
; pub type Topic = VariadicValue; #[derive(Debug, PartialEq, Deserialize)] +#[serde(deny_unknown_fields)] pub struct Filter { #[serde(rename="fromBlock")] pub from_block: Option, diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs index a77096fbf..e7cbbd255 100644 --- a/rpc/src/v1/types/index.rs +++ b/rpc/src/v1/types/index.rs @@ -30,7 +30,7 @@ impl Index { impl Deserialize for Index { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.visit(IndexVisitor) + deserializer.deserialize(IndexVisitor) } } @@ -41,8 +41,8 @@ impl Visitor for IndexVisitor { fn visit_str(&mut self, value: &str) -> Result where E: Error { match value { - _ if value.starts_with("0x") => usize::from_str_radix(&value[2..], 16).map(Index).map_err(|_| Error::syntax("invalid index")), - _ => value.parse::().map(Index).map_err(|_| Error::syntax("invalid index")) + _ if value.starts_with("0x") => usize::from_str_radix(&value[2..], 16).map(Index).map_err(|_| Error::custom("invalid index")), + _ => value.parse::().map(Index).map_err(|_| Error::custom("invalid index")) } } diff --git a/util/Cargo.toml b/util/Cargo.toml index 3c742715e..6a18f80de 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -18,7 +18,7 @@ time = "0.1.34" tiny-keccak = "1.0" rocksdb = { git = "https://github.com/arkpar/rust-rocksdb.git" } lazy_static = "0.1" -eth-secp256k1 = { git = "https://github.com/arkpar/rust-secp256k1.git" } +eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" } rust-crypto = "0.2.34" elastic-array = "0.4" heapsize = "0.3" @@ -26,7 +26,7 @@ itertools = "0.4" crossbeam = "0.2" slab = "0.1" sha3 = { path = "sha3" } -serde = "0.6.7" +serde = "0.7.0" clippy = { version = "0.0.44", optional = true } json-tests = { path = "json-tests" } rustc_version = "0.1.0" diff --git a/util/src/hash.rs b/util/src/hash.rs index a6e8f7950..88c57371e 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -239,7 +239,7 @@ macro_rules! impl_hash { where S: serde::Serializer { let mut hex = "0x".to_owned(); hex.push_str(self.to_hex().as_ref()); - serializer.visit_str(hex.as_ref()) + serializer.serialize_str(hex.as_ref()) } } @@ -254,10 +254,10 @@ macro_rules! impl_hash { fn visit_str(&mut self, value: &str) -> Result where E: serde::Error { // 0x + len if value.len() != 2 + $size * 2 { - return Err(serde::Error::syntax("Invalid length.")); + return Err(serde::Error::custom("Invalid length.")); } - value[2..].from_hex().map(|ref v| $from::from_slice(v)).map_err(|_| serde::Error::syntax("Invalid valid hex.")) + value[2..].from_hex().map(|ref v| $from::from_slice(v)).map_err(|_| serde::Error::custom("Invalid valid hex.")) } fn visit_string(&mut self, value: String) -> Result where E: serde::Error { @@ -265,7 +265,7 @@ macro_rules! impl_hash { } } - deserializer.visit(HashVisitor) + deserializer.deserialize(HashVisitor) } } diff --git a/util/src/uint.rs b/util/src/uint.rs index 5a2730126..7c75771b7 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -760,7 +760,7 @@ macro_rules! construct_uint { self.to_bytes(&mut bytes); let len = cmp::max((self.bits() + 7) / 8, 1); hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref()); - serializer.visit_str(hex.as_ref()) + serializer.serialize_str(hex.as_ref()) } } From b2dd6ded1dbfc207ffc5275e1f17b04229bb9e1f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Feb 2016 15:02:05 +0100 Subject: [PATCH 246/753] Update discovery.rs --- util/src/network/discovery.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index e00837f8c..f072b0a66 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -349,7 +349,7 @@ impl Discovery { } } - fn check_timestamp(&self, timestamp: u64) -> Result<(), NetworkError>{ + fn check_timestamp(&self, timestamp: u64) -> Result<(), NetworkError> { if self.check_timestamps && timestamp < time::get_time().sec as u64{ debug!(target: "discovery", "Expired packet"); return Err(NetworkError::Expired); From 213bfc4417b819d88c6c6eb0d7159115d4000f81 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Feb 2016 15:05:13 +0100 Subject: [PATCH 247/753] Update handshake.rs --- util/src/network/handshake.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 30dd70c79..c3a898900 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -282,12 +282,12 @@ impl Handshake { } Err(_) => { // Try to interpret as EIP-8 packet - let size = ((data[0] as u16) << 8 | (data[1] as u16)) as usize; - if size < (V4_ACK_PACKET_SIZE - 2) { - debug!(target:"net", "Wrong EIP8 ack packet size"); + let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + if total < V4_ACK_PACKET_SIZE { + debug!(target: "net", "Wrong EIP8 ack packet size"); return Err(From::from(NetworkError::BadProtocol)); } - let rest = size - data.len() + 2; + let rest = total - data.len(); self.state = HandshakeState::ReadingAckEip8; self.connection.expect(rest); } From faa634789604e2a57c6aa223d1d0070b19bedc31 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Feb 2016 15:07:21 +0100 Subject: [PATCH 248/753] Update handshake.rs --- util/src/network/handshake.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index c3a898900..e6f14c6fc 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -239,12 +239,12 @@ impl Handshake { } Err(_) => { // Try to interpret as EIP-8 packet - let size = ((data[0] as u16) << 8 | (data[1] as u16)) as usize; - if size < V4_AUTH_PACKET_SIZE - 2 { + let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + if total < V4_AUTH_PACKET_SIZE { debug!(target:"net", "Wrong EIP8 auth packet size"); return Err(From::from(NetworkError::BadProtocol)); } - let rest = size - data.len() + 2; + let rest = total - data.len(); self.state = HandshakeState::ReadingAuthEip8; self.connection.expect(rest); } @@ -284,7 +284,7 @@ impl Handshake { // Try to interpret as EIP-8 packet let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; if total < V4_ACK_PACKET_SIZE { - debug!(target: "net", "Wrong EIP8 ack packet size"); + debug!(target:"net", "Wrong EIP8 ack packet size"); return Err(From::from(NetworkError::BadProtocol)); } let rest = total - data.len(); From ec8c1cb5f9e0bb435770df9a56d25d6a3a2b05a4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Feb 2016 15:49:44 +0100 Subject: [PATCH 249/753] Make "random" trie tests fully determinate. --- util/src/trie/standardmap.rs | 25 +++++++++++----- util/src/trie/triedbmut.rs | 58 ++++++++++++------------------------ 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/util/src/trie/standardmap.rs b/util/src/trie/standardmap.rs index 98a5ae0f0..b7f3a9500 100644 --- a/util/src/trie/standardmap.rs +++ b/util/src/trie/standardmap.rs @@ -20,6 +20,7 @@ extern crate rand; use bytes::*; use sha3::*; use hash::*; +use rlp::encode; /// Alphabet to use when creating words for insertion into tries. pub enum Alphabet { @@ -39,6 +40,8 @@ pub enum ValueMode { Mirror, /// Randomly (50:50) 1 or 32 byte randomly string. Random, + /// RLP-encoded index. + Index, } /// Standard test map for profiling tries. @@ -89,19 +92,27 @@ impl StandardMap { /// Create the standard map (set of keys and values) for the object's fields. pub fn make(&self) -> Vec<(Bytes, Bytes)> { + self.make_with(&mut H256::new()) + } + + /// Create the standard map (set of keys and values) for the object's fields, using the given seed. + pub fn make_with(&self, seed: &mut H256) -> Vec<(Bytes, Bytes)> { let low = b"abcdef"; let mid = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..self.count { + for index in 0..self.count { let k = match self.alphabet { - Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, &mut seed), - Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, &mut seed), - Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, &mut seed), - Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, &mut seed), + Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, seed), + Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, seed), + Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, seed), + Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, seed), + }; + let v = match self.value_mode { + ValueMode::Mirror => k.clone(), + ValueMode::Random => Self::random_value(seed), + ValueMode::Index => encode(&index).to_vec(), }; - let v = match self.value_mode { ValueMode::Mirror => k.clone(), ValueMode::Random => Self::random_value(&mut seed) }; d.push((k, v)) } d diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 2b4567264..829c1e518 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -687,31 +687,10 @@ mod tests { use super::*; use nibbleslice::*; use rlp::*; - use rand::random; - use std::collections::HashSet; - use bytes::{ToPretty,Bytes,Populatable}; + use bytes::ToPretty; use super::super::node::*; use super::super::trietraits::*; - - fn random_key(alphabet: &[u8], min_count: usize, journal_count: usize) -> Vec { - let mut ret: Vec = Vec::new(); - let r = min_count + if journal_count > 0 {random::() % journal_count} else {0}; - for _ in 0..r { - ret.push(alphabet[random::() % alphabet.len()]); - } - ret - } - - fn random_value_indexed(j: usize) -> Bytes { - match random::() % 2 { - 0 => encode(&j).to_vec(), - _ => { - let mut h = H256::new(); - h.as_slice_mut()[31] = j as u8; - encode(&h).to_vec() - }, - } - } + use super::super::standardmap::*; fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &[(Vec, Vec)]) -> TrieDBMut<'db> { let mut t = TrieDBMut::new(db, root); @@ -756,20 +735,18 @@ mod tests { };*/ // panic!(); + let mut seed = H256::new(); for test_i in 0..1 { if test_i % 50 == 0 { debug!("{:?} of 10000 stress tests done", test_i); } - let mut x: Vec<(Vec, Vec)> = Vec::new(); - let mut got: HashSet> = HashSet::new(); - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - for j in 0..100usize { - let key = random_key(alphabet, 5, 0); - if !got.contains(&key) { - x.push((key.clone(), random_value_indexed(j))); - got.insert(key); - } - } + let x = StandardMap { + alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), + min_key: 5, + journal_key: 0, + value_mode: ValueMode::Index, + count: 100, + }.make_with(&mut seed); let real = trie_root(x.clone()); let mut memdb = MemoryDB::new(); @@ -1049,13 +1026,16 @@ mod tests { #[test] fn stress() { + let mut seed = H256::new(); for _ in 0..50 { - let mut x: Vec<(Vec, Vec)> = Vec::new(); - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - for j in 0..4u32 { - let key = random_key(alphabet, 5, 1); - x.push((key, encode(&j).to_vec())); - } + let x = StandardMap { + alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), + min_key: 5, + journal_key: 0, + value_mode: ValueMode::Index, + count: 4, + }.make_with(&mut seed); + let real = trie_root(x.clone()); let mut memdb = MemoryDB::new(); let mut root = H256::new(); From b60b84fe67f1b77aee61e7c1f41c96f427c1c28b Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 15:56:41 +0100 Subject: [PATCH 250/753] use transient-hashmap from crates.io --- Cargo.lock | 4 ++-- rpc/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 124e3911e..622ac2e54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -212,7 +212,7 @@ dependencies = [ "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "transient-hashmap 0.1.0 (git+https://github.com/debris/transient-hashmap)", + "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -795,7 +795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "transient-hashmap" version = "0.1.0" -source = "git+https://github.com/debris/transient-hashmap#e21bf844277785504ddc30ee22d2a709103d4992" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index edc749180..3c9851ed3 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -19,7 +19,7 @@ ethsync = { path = "../sync" } clippy = { version = "0.0.44", optional = true } rustc-serialize = "0.3" serde_macros = { version = "0.6.13", optional = true } -transient-hashmap = { git = "https://github.com/debris/transient-hashmap" } +transient-hashmap = "0.1" [build-dependencies] serde_codegen = { version = "0.6.13", optional = true } From e6bab014d1ca0e40726b29c7b88c7036f2c8fc2e Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 27 Feb 2016 16:40:22 +0100 Subject: [PATCH 251/753] Fixed outgoing ack size --- util/src/network/handshake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index e6f14c6fc..0cfcbac3a 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -367,7 +367,7 @@ impl Handshake { let encoded = rlp.drain(); let len = (encoded.len() + ECIES_OVERHEAD) as u16; - let prefix = [ (len & 0xff) as u8, (len >> 8) as u8 ]; + let prefix = [ (len >> 8) as u8, (len & 0xff) as u8 ]; let message = try!(crypto::ecies::encrypt(&self.id, &prefix, &encoded)); self.ack_cipher.extend_from_slice(&prefix); self.ack_cipher.extend_from_slice(&message); From dc604c21b5bdc4dff5e39f8abd4bbb74be50b1d1 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 27 Feb 2016 18:43:38 +0300 Subject: [PATCH 252/753] most complete carry test ever --- util/src/uint.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/util/src/uint.rs b/util/src/uint.rs index 97e7eecb3..af0e4add0 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1537,6 +1537,76 @@ mod tests { assert_eq!(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]), result); } + #[test] + fn u256_multi_carry_all() { + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX-1, 0, 0]), result); + + let (result, _) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([0, 1, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX-1, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul( + U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, 0, 0]), result); + } #[test] fn u256_multi_muls() { From 4bdd5267b025822b0ec16bd89b3d61432b4f8eaf Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 27 Feb 2016 16:44:47 +0100 Subject: [PATCH 253/753] Ack size test --- util/src/network/handshake.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 0cfcbac3a..cca133ba9 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -481,6 +481,9 @@ mod test { h.read_auth_eip8(&secret, &auth[super::V4_AUTH_PACKET_SIZE..]).unwrap(); assert_eq!(h.state, super::HandshakeState::StartSession); check_auth(&h, 56); + let ack = h.ack_cipher.clone(); + let total = (((ack[0] as u16) << 8 | (ack[1] as u16)) as usize) + 2; + assert_eq!(ack.len(), total); } #[test] From 019638628c68ea6020cd90938bab85e998c7de6f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 27 Feb 2016 18:45:19 +0300 Subject: [PATCH 254/753] removed duplicates --- util/src/uint.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index af0e4add0..ca8e2f4fd 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1639,19 +1639,9 @@ mod tests { let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); assert_eq!(U256([0, 10, 0, 0]), result); - let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); - assert_eq!(U256([1, ::std::u64::MAX-1, 0, 0]), result); - - let (result, _) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert_eq!(U256([0, 0, 0, 0]), result); - let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) - .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); - assert_eq!(U256([1, 0, 0, 0]), result); - let x1 = U256::from_str("0000000000000000000000000000000000000000000000000000012365124623").unwrap(); let x2sqr_right = U256::from_str("000000000000000000000000000000000000000000014baeef72e0378e2328c9").unwrap(); let x1sqr = x1 * x1; From 6a0e9c5ed0d88a83198f0abc8c86564a155d4893 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 27 Feb 2016 18:55:07 +0300 Subject: [PATCH 255/753] tabified --- util/src/uint.rs | 190 +++++++++++++++++++++++------------------------ 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index ca8e2f4fd..b998784aa 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1512,135 +1512,135 @@ mod tests { } - #[test] - fn u256_multi_subs() { - let (result, _) = U256([0, 0, 0, 0]).overflowing_sub(U256([0, 0, 0, 0])); - assert_eq!(result, U256([0, 0, 0, 0])); + #[test] + fn u256_multi_subs() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_sub(U256([0, 0, 0, 0])); + assert_eq!(result, U256([0, 0, 0, 0])); - let (result, _) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 0, 1])); - assert_eq!(result, U256([0, 0, 0, 0])); + let (result, _) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 0, 1])); + assert_eq!(result, U256([0, 0, 0, 0])); - let (_, overflow) = U256([0, 0, 2, 1]).overflowing_sub(U256([0, 0, 3, 1])); - assert!(overflow); + let (_, overflow) = U256([0, 0, 2, 1]).overflowing_sub(U256([0, 0, 3, 1])); + assert!(overflow); - let (result, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) - .overflowing_sub(U256([::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2])); - assert!(!overflow); - assert_eq!(U256([::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1]), result); + let (result, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_sub(U256([::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1]), result); - let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 1, 0])); - assert!(!overflow); - assert_eq!(U256([0, 0, ::std::u64::MAX, 0]), result); + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 1, 0])); + assert!(!overflow); + assert_eq!(U256([0, 0, ::std::u64::MAX, 0]), result); - let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([1, 0, 0, 0])); - assert!(!overflow); - assert_eq!(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]), result); - } + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([1, 0, 0, 0])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + } #[test] fn u256_multi_carry_all() { - let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); - assert_eq!(U256([1, ::std::u64::MAX-1, 0, 0]), result); + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX-1, 0, 0]), result); - let (result, _) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); - assert_eq!(U256([0, 1, ::std::u64::MAX-1, 0]), result); + let (result, _) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([0, 1, ::std::u64::MAX-1, 0]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); - assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); - let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); - assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); - assert_eq!(U256([1, 0, ::std::u64::MAX-1, ::std::u64::MAX]), result); + assert_eq!(U256([1, 0, ::std::u64::MAX-1, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); - assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); - assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); - let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul( + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul( U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); - assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) .overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); - assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); - assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); - assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); - assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); - assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); - assert_eq!(U256([1, 0, 0, ::std::u64::MAX-1]), result); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX-1]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); - assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); - assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); - let (result, _) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert_eq!(U256([0, 0, 0, 0]), result); + let (result, _) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, 0]), result); - let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); - let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); - assert_eq!(U256([1, 0, 0, 0]), result); + assert_eq!(U256([1, 0, 0, 0]), result); } #[test] fn u256_multi_muls() { use hash::*; - let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); - assert_eq!(U256([0, 0, 0, 0]), result); + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); - let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); - assert_eq!(U256([1, 0, 0, 0]), result); + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([1, 0, 0, 0]), result); - let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); - assert_eq!(U256([25, 0, 0, 0]), result); + let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); + assert_eq!(U256([25, 0, 0, 0]), result); - let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); - assert_eq!(U256([0, 0, 25, 0]), result); + let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 25, 0]), result); - let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); - assert_eq!(U256([0, 0, 0, 1]), result); + let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 1]), result); - let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); - assert_eq!(U256([0, 0, 0, 10]), result); + let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 10]), result); - let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); - assert_eq!(U256([0, 0, 0, 5]), result); + let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 0, 5]), result); - let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); - assert_eq!(U256([0, 0, 0, 0]), result); + let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); - let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); - assert_eq!(U256([0, 10, 0, 0]), result); + let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 10, 0, 0]), result); - let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); let x1 = U256::from_str("0000000000000000000000000000000000000000000000000000012365124623").unwrap(); let x2sqr_right = U256::from_str("000000000000000000000000000000000000000000014baeef72e0378e2328c9").unwrap(); @@ -1662,32 +1662,32 @@ mod tests { #[test] fn u256_multi_muls_overflow() { - let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); - assert!(!overflow); + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert!(!overflow); - let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert!(!overflow); + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(!overflow); - let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert!(overflow); + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(overflow); - let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 1, 0, 0])); - assert!(!overflow); + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 1, 0, 0])); + assert!(!overflow); - let (_, overflow) = U256([0, 1, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 1, 0, ::std::u64::MAX])); - assert!(overflow); + let (_, overflow) = U256([0, 1, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 1, 0, ::std::u64::MAX])); + assert!(overflow); - let (_, overflow) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([0, ::std::u64::MAX, 0, 0])); - assert!(!overflow); + let (_, overflow) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([0, ::std::u64::MAX, 0, 0])); + assert!(!overflow); - let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([10, 0, 0, 0])); - assert!(!overflow); + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([10, 0, 0, 0])); + assert!(!overflow); - let (_, overflow) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX / 2])); - assert!(!overflow); + let (_, overflow) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX / 2])); + assert!(!overflow); - let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); - assert!(overflow); + let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert!(overflow); } } From 1cc719d4135df70a390e132b16776d0d0f03e292 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 19:17:29 +0100 Subject: [PATCH 256/753] description for prepare_block_blooms_update function --- ethcore/src/blockchain/blockchain.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index b785629be..e09713c3b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -588,7 +588,20 @@ impl BlockChain { /// This functions returns modified blocks blooms. /// - /// TODO: this function needs comprehensive description. + /// To accelerate blooms lookups, blomms are stored in multiple + /// layers (BLOOM_LEVELS, currently 3). + /// ChainFilter is responsible for building and rebuilding these layers. + /// It returns them in HashMap, where values are Blooms and + /// keys are BloomIndexes. BloomIndex represents bloom location on one + /// of these layers. + /// + /// To reduce number of queries to databse, block blooms are stored + /// in BlocksBlooms structure which contains info about several + /// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms. + /// + /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex) + /// to bloom location in database (BlocksBloomLocation). + /// fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); let header = block.header_view(); From 1481f3f477e5499adea607e0264b03495fae2473 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 27 Feb 2016 19:27:34 +0100 Subject: [PATCH 257/753] replaced match with if to shorten the code --- ethcore/src/blockchain/blockchain.rs | 29 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index e09713c3b..8aa0fffdc 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -488,25 +488,24 @@ impl BlockChain { hash: hash, number: number, total_difficulty: total_difficulty, - location: match is_new_best { - false => BlockLocation::Branch, - true => { - // on new best block we need to make sure that all ancestors - // are moved to "canon chain" - // find the route between old best block and the new one - let best_hash = self.best_block_hash(); - let route = self.tree_route(best_hash, parent_hash); + location: if is_new_best { + // on new best block we need to make sure that all ancestors + // are moved to "canon chain" + // find the route between old best block and the new one + let best_hash = self.best_block_hash(); + let route = self.tree_route(best_hash, parent_hash); - assert_eq!(number, parent_details.number + 1); + assert_eq!(number, parent_details.number + 1); - match route.blocks.len() { - 0 => BlockLocation::CanonChain, - _ => BlockLocation::BranchBecomingCanonChain { - ancestor: route.ancestor, - route: route.blocks.into_iter().skip(route.index).collect() - } + match route.blocks.len() { + 0 => BlockLocation::CanonChain, + _ => BlockLocation::BranchBecomingCanonChain { + ancestor: route.ancestor, + route: route.blocks.into_iter().skip(route.index).collect() } } + } else { + BlockLocation::Branch } } } From be4b0472c8b639cbd0694b8b69517e3315b476e3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Feb 2016 10:33:57 +0100 Subject: [PATCH 258/753] Morden switch to Homestead rules at #494,000. --- ethcore/res/ethereum/morden.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 2e45c2edd..e9f8e0e99 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -3,7 +3,7 @@ "engineName": "Ethash", "params": { "accountStartNonce": "0x0100000", - "frontierCompatibilityModeLimit": "0x10c8e0", + "frontierCompatibilityModeLimit": "0x789b0", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", From 77bfe5ae0055ee8286e663f7433028d59d874188 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 29 Feb 2016 11:58:33 +0100 Subject: [PATCH 259/753] jsonrpc uses weak pointers to client --- parity/main.rs | 6 +++--- rpc/src/v1/impls/eth.rs | 43 +++++++++++++++++++++-------------------- rpc/src/v1/impls/mod.rs | 10 ++++++++++ rpc/src/v1/impls/net.rs | 12 ++++++------ 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 6415dfc33..3d0d183a3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -148,9 +148,9 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_dom let mut server = rpc::HttpServer::new(1); server.add_delegate(Web3Client::new().to_delegate()); - server.add_delegate(EthClient::new(client.clone(), sync.clone()).to_delegate()); - server.add_delegate(EthFilterClient::new(client).to_delegate()); - server.add_delegate(NetClient::new(sync).to_delegate()); + server.add_delegate(EthClient::new(&client, &sync).to_delegate()); + server.add_delegate(EthFilterClient::new(&client).to_delegate()); + server.add_delegate(NetClient::new(&sync).to_delegate()); server.start_async(url, cors_domain); } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 689afd019..00bce5437 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Eth rpc implementation. -use std::sync::Arc; +use std::sync::{Arc, Weak}; use ethsync::{EthSync, SyncState}; use jsonrpc_core::*; use util::hash::*; @@ -29,21 +29,22 @@ use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncIn /// Eth rpc implementation. pub struct EthClient { - client: Arc, - sync: Arc + client: Weak, + sync: Weak } impl EthClient { /// Creates new EthClient. - pub fn new(client: Arc, sync: Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc) -> Self { EthClient { - client: client, - sync: sync + client: Arc::downgrade(client), + sync: Arc::downgrade(sync) } } fn block(&self, id: BlockId, include_txs: bool) -> Result { - match (self.client.block(id.clone()), self.client.block_total_difficulty(id)) { + let client = take_weak!(self.client); + match (client.block(id.clone()), client.block_total_difficulty(id)) { (Some(bytes), Some(total_difficulty)) => { let block_view = BlockView::new(&bytes); let view = block_view.header_view(); @@ -78,9 +79,9 @@ impl EthClient { _ => Ok(Value::Null) } } - + fn transaction(&self, id: TransactionId) -> Result { - match self.client.transaction(id) { + match take_weak!(self.client).transaction(id) { Some(t) => to_value(&Transaction::from(t)), None => Ok(Value::Null) } @@ -90,7 +91,7 @@ impl EthClient { impl Eth for EthClient { fn protocol_version(&self, params: Params) -> Result { match params { - Params::None => to_value(&U256::from(self.sync.status().protocol_version)), + Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)), _ => Err(Error::invalid_params()) } } @@ -98,12 +99,12 @@ impl Eth for EthClient { fn syncing(&self, params: Params) -> Result { match params { Params::None => { - let status = self.sync.status(); + let status = take_weak!(self.sync).status(); let res = match status.state { SyncState::NotSynced | SyncState::Idle => SyncStatus::None, SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks => SyncStatus::Info(SyncInfo { starting_block: U256::from(status.start_block_number), - current_block: U256::from(self.client.chain_info().best_block_number), + current_block: U256::from(take_weak!(self.client).chain_info().best_block_number), highest_block: U256::from(status.highest_block_number.unwrap_or(status.start_block_number)) }) }; @@ -146,14 +147,14 @@ impl Eth for EthClient { fn block_number(&self, params: Params) -> Result { match params { - Params::None => to_value(&U256::from(self.client.chain_info().best_block_number)), + Params::None => to_value(&U256::from(take_weak!(self.client).chain_info().best_block_number)), _ => Err(Error::invalid_params()) } } fn block_transaction_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { + .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), None => Ok(Value::Null) }) @@ -161,7 +162,7 @@ impl Eth for EthClient { fn block_uncles_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { + .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), None => Ok(Value::Null) }) @@ -170,7 +171,7 @@ impl Eth for EthClient { // TODO: do not ignore block number param fn code_at(&self, params: Params) -> Result { from_params::<(Address, BlockNumber)>(params) - .and_then(|(address, _block_number)| to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new))) + .and_then(|(address, _block_number)| to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new))) } fn block_by_hash(&self, params: Params) -> Result { @@ -201,7 +202,7 @@ impl Eth for EthClient { fn logs(&self, params: Params) -> Result { from_params::<(Filter,)>(params) .and_then(|(filter,)| { - let logs = self.client.logs(filter.into()) + let logs = take_weak!(self.client).logs(filter.into()) .into_iter() .map(From::from) .collect::>(); @@ -212,14 +213,14 @@ impl Eth for EthClient { /// Eth filter rpc implementation. pub struct EthFilterClient { - client: Arc + client: Weak } impl EthFilterClient { /// Creates new Eth filter client. - pub fn new(client: Arc) -> Self { + pub fn new(client: &Arc) -> Self { EthFilterClient { - client: client + client: Arc::downgrade(client) } } } @@ -234,6 +235,6 @@ impl EthFilter for EthFilterClient { } fn filter_changes(&self, _: Params) -> Result { - to_value(&self.client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) + to_value(&take_weak!(self.client).chain_info().best_block_hash).map(|v| Value::Array(vec![v])) } } diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index bc8b436fd..d9102b1db 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -15,6 +15,16 @@ // along with Parity. If not, see . //! Ethereum rpc interface implementation. + +macro_rules! take_weak { + ($weak: expr) => { + match $weak.upgrade() { + Some(arc) => arc, + None => return Err(Error::internal_error()) + } + } +} + mod web3; mod eth; mod net; diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index b36042dba..9e24caad2 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -15,31 +15,31 @@ // along with Parity. If not, see . //! Net rpc implementation. -use std::sync::Arc; +use std::sync::{Arc, Weak}; use jsonrpc_core::*; use ethsync::EthSync; use v1::traits::Net; /// Net rpc implementation. pub struct NetClient { - sync: Arc + sync: Weak } impl NetClient { /// Creates new NetClient. - pub fn new(sync: Arc) -> Self { + pub fn new(sync: &Arc) -> Self { NetClient { - sync: sync + sync: Arc::downgrade(sync) } } } impl Net for NetClient { fn version(&self, _: Params) -> Result { - Ok(Value::U64(self.sync.status().protocol_version as u64)) + Ok(Value::U64(take_weak!(self.sync).status().protocol_version as u64)) } fn peer_count(&self, _params: Params) -> Result { - Ok(Value::U64(self.sync.status().num_peers as u64)) + Ok(Value::U64(take_weak!(self.sync).status().num_peers as u64)) } } From 5357f581315fc6b5e179c589537b97322e6e9998 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 29 Feb 2016 12:04:58 +0100 Subject: [PATCH 260/753] uncomment state transition tests --- ethcore/src/json_tests/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index b5f28444a..f6b5751a7 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -115,7 +115,7 @@ declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} -//declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} +declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} From 9b9e054dc35ae8ca7953a43c8fd3a8c4aa5bfc52 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 29 Feb 2016 14:29:51 +0300 Subject: [PATCH 261/753] changing x64 asm config --- util/Cargo.toml | 2 +- util/build.rs | 10 +++++++++- util/src/lib.rs | 2 +- util/src/uint.rs | 12 ++++++------ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/util/Cargo.toml b/util/Cargo.toml index 6a18f80de..b7eafd905 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -39,7 +39,7 @@ target_info = "0.1" [features] default = [] dev = ["clippy"] -x64asm = [] [build-dependencies] vergen = "*" +rustc_version = "0.1" diff --git a/util/build.rs b/util/build.rs index 32ee30472..20fd8c15f 100644 --- a/util/build.rs +++ b/util/build.rs @@ -1,6 +1,14 @@ extern crate vergen; +extern crate rustc_version; + + use vergen::*; +use rustc_version::{version_meta, Channel}; fn main() { vergen(OutputFns::all()).unwrap(); -} \ No newline at end of file + + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=x64asm"); + } +} diff --git a/util/src/lib.rs b/util/src/lib.rs index be1e788c9..2a47eb438 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -16,7 +16,7 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(feature="x64asm", feature(asm))] +#![cfg_attr(x64asm, feature(asm))] #![cfg_attr(feature="dev", plugin(clippy))] // Clippy settings diff --git a/util/src/uint.rs b/util/src/uint.rs index 67a6f2ff4..517b7a29f 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -51,7 +51,7 @@ macro_rules! impl_map_from { } } -#[cfg(not(all(feature="x64asm", target_arch="x86_64")))] +#[cfg(not(all(x64asm, target_arch="x86_64")))] macro_rules! uint_overflowing_add { ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) @@ -89,7 +89,7 @@ macro_rules! uint_overflowing_add_reg { } -#[cfg(all(feature="x64asm", target_arch="x86_64"))] +#[cfg(all(x64asm, target_arch="x86_64"))] macro_rules! uint_overflowing_add { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -165,7 +165,7 @@ macro_rules! uint_overflowing_add { ) } -#[cfg(not(all(feature="x64asm", target_arch="x86_64")))] +#[cfg(not(all(x64asm, target_arch="x86_64")))] macro_rules! uint_overflowing_sub { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let res = overflowing!((!$other).overflowing_add(From::from(1u64))); @@ -174,7 +174,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(feature="x64asm", target_arch="x86_64"))] +#[cfg(all(x64asm, target_arch="x86_64"))] macro_rules! uint_overflowing_sub { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -250,7 +250,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(feature="x64asm", target_arch="x86_64"))] +#[cfg(all(x64asm, target_arch="x86_64"))] macro_rules! uint_overflowing_mul { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -370,7 +370,7 @@ macro_rules! uint_overflowing_mul { ) } -#[cfg(not(all(feature="x64asm", target_arch="x86_64")))] +#[cfg(not(all(x64asm, target_arch="x86_64")))] macro_rules! uint_overflowing_mul { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) From e0c158c12f53088fbeefd75707c9b2ffabf6a4e9 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 29 Feb 2016 14:40:59 +0300 Subject: [PATCH 262/753] removed space --- util/build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/util/build.rs b/util/build.rs index 20fd8c15f..b8346c97d 100644 --- a/util/build.rs +++ b/util/build.rs @@ -1,7 +1,6 @@ extern crate vergen; extern crate rustc_version; - use vergen::*; use rustc_version::{version_meta, Channel}; From 6197b3ee60a8271449f186d730cc362917f4fef8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Feb 2016 12:47:34 +0100 Subject: [PATCH 263/753] New provisional Homestead block. --- ethcore/res/ethereum/frontier.json | 4 ++-- ethcore/res/ethereum/frontier_like_test.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index 6e31a2fce..cd66ad3f1 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -1,9 +1,9 @@ { - "name": "Frontier", + "name": "Frontier/Homestead", "engineName": "Ethash", "params": { "accountStartNonce": "0x00", - "frontierCompatibilityModeLimit": "0x10c8e0", + "frontierCompatibilityModeLimit": "0x118c30", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 553bb8018..3e4108566 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -3,7 +3,7 @@ "engineName": "Ethash", "params": { "accountStartNonce": "0x00", - "frontierCompatibilityModeLimit": "0x10c8e0", + "frontierCompatibilityModeLimit": "0x118c30", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", From 06623333d9de984c22eaa6adf0e5eed2d168070f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 29 Feb 2016 15:23:43 +0300 Subject: [PATCH 264/753] fix tabs --- util/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/build.rs b/util/build.rs index b8346c97d..2b581642b 100644 --- a/util/build.rs +++ b/util/build.rs @@ -7,7 +7,7 @@ use rustc_version::{version_meta, Channel}; fn main() { vergen(OutputFns::all()).unwrap(); - if let Channel::Nightly = version_meta().channel { + if let Channel::Nightly = version_meta().channel { println!("cargo:rustc-cfg=x64asm"); - } + } } From 83b8e7df5a6f4bdee8e0ddc208fe44029d4a2517 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Feb 2016 14:57:41 +0100 Subject: [PATCH 265/753] Initial refactor and block closing. --- ethcore/src/block.rs | 53 +++++++++++++++++++------------------------ ethcore/src/client.rs | 39 +++++++++++++++++++++++++++---- ethcore/src/header.rs | 2 +- parity/main.rs | 1 - 4 files changed, 59 insertions(+), 36 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 70c6c2fb2..28005b17e 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -155,9 +155,9 @@ pub struct OpenBlock<'x> { /// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, /// and collected the uncles. /// -/// There is no function available to push a transaction. If you want that you'll need to `reopen()` it. -pub struct ClosedBlock<'x> { - open_block: OpenBlock<'x>, +/// There is no function available to push a transaction. +pub struct ClosedBlock { + block: ExecutedBlock, uncle_bytes: Bytes, } @@ -181,7 +181,7 @@ impl<'x> OpenBlock<'x> { r.block.base.header.set_number(parent.number() + 1); r.block.base.header.set_author(author); r.block.base.header.set_extra_data(extra_data); - r.block.base.header.set_timestamp_now(); + r.block.base.header.set_timestamp_now(parent.timestamp()); engine.populate_from_parent(&mut r.block.base.header, parent); engine.on_new_block(&mut r.block); @@ -259,7 +259,7 @@ impl<'x> OpenBlock<'x> { } /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. - pub fn close(self) -> ClosedBlock<'x> { + pub fn close(self) -> ClosedBlock { let mut s = self; s.engine.on_close_block(&mut s.block); s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect()); @@ -271,7 +271,10 @@ impl<'x> OpenBlock<'x> { s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used); s.block.base.header.note_dirty(); - ClosedBlock::new(s, uncle_bytes) + ClosedBlock { + block: s.block, + uncle_bytes: uncle_bytes, + } } } @@ -279,38 +282,28 @@ impl<'x> IsBlock for OpenBlock<'x> { fn block(&self) -> &ExecutedBlock { &self.block } } -impl<'x> IsBlock for ClosedBlock<'x> { - fn block(&self) -> &ExecutedBlock { &self.open_block.block } +impl<'x> IsBlock for ClosedBlock { + fn block(&self) -> &ExecutedBlock { &self.block } } -impl<'x> ClosedBlock<'x> { - fn new(open_block: OpenBlock<'x>, uncle_bytes: Bytes) -> Self { - ClosedBlock { - open_block: open_block, - uncle_bytes: uncle_bytes, - } - } - +impl ClosedBlock { /// Get the hash of the header without seal arguments. pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) } /// Provide a valid seal in order to turn this into a `SealedBlock`. /// /// NOTE: This does not check the validity of `seal` with the engine. - pub fn seal(self, seal: Vec) -> Result { + pub fn seal(self, engine: &Engine, seal: Vec) -> Result { let mut s = self; - if seal.len() != s.open_block.engine.seal_fields() { - return Err(BlockError::InvalidSealArity(Mismatch{expected: s.open_block.engine.seal_fields(), found: seal.len()})); + if seal.len() != engine.seal_fields() { + return Err(BlockError::InvalidSealArity(Mismatch{expected: engine.seal_fields(), found: seal.len()})); } - s.open_block.block.base.header.set_seal(seal); - Ok(SealedBlock { block: s.open_block.block, uncle_bytes: s.uncle_bytes }) + s.block.base.header.set_seal(seal); + Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) } - /// Turn this back into an `OpenBlock`. - pub fn reopen(self) -> OpenBlock<'x> { self.open_block } - /// Drop this object and return the underlieing database. - pub fn drain(self) -> JournalDB { self.open_block.block.state.drop().1 } + pub fn drain(self) -> JournalDB { self.block.state.drop().1 } } impl SealedBlock { @@ -332,7 +325,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact<'x>(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> { +pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce()); @@ -350,14 +343,14 @@ pub fn enact<'x>(header: &Header, transactions: &[SignedTransaction], uncles: &[ } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes<'x>(block_bytes: &[u8], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> { +pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified<'x>(block: &PreVerifiedBlock, engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> { +pub fn enact_verified(block: &PreVerifiedBlock, engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { let view = BlockView::new(&block.bytes); enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) } @@ -365,7 +358,7 @@ pub fn enact_verified<'x>(block: &PreVerifiedBlock, engine: &'x Engine, db: Jour /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); - Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(header.seal()))) + Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal()))) } #[cfg(test)] @@ -386,7 +379,7 @@ mod tests { let last_hashes = vec![genesis_header.hash()]; let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let b = b.close(); - let _ = b.seal(vec![]); + let _ = b.seal(engine.deref(), vec![]); } #[test] diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 5d71eed84..c378fa449 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -193,6 +193,9 @@ pub struct Client { report: RwLock, import_lock: Mutex<()>, panic_handler: Arc, + + // for sealing... + _sealing_block: Mutex>, } const HISTORY: u64 = 1000; @@ -228,7 +231,8 @@ impl Client { block_queue: RwLock::new(block_queue), report: RwLock::new(Default::default()), import_lock: Mutex::new(()), - panic_handler: panic_handler + panic_handler: panic_handler, + _sealing_block: Mutex::new(None), })) } @@ -237,10 +241,10 @@ impl Client { self.block_queue.write().unwrap().flush(); } - fn build_last_hashes(&self, header: &Header) -> LastHashes { + fn build_last_hashes(&self, parent_hash: H256) -> LastHashes { let mut last_hashes = LastHashes::new(); last_hashes.resize(256, H256::new()); - last_hashes[0] = header.parent_hash.clone(); + last_hashes[0] = parent_hash; let chain = self.chain.read().unwrap(); for i in 0..255 { match chain.block_details(&last_hashes[i]) { @@ -273,7 +277,7 @@ impl Client { // Enact Verified Block let parent = chain_has_parent.unwrap(); - let last_hashes = self.build_last_hashes(header); + let last_hashes = self.build_last_hashes(header.parent_hash.clone()); let db = self.state_db.lock().unwrap().clone(); let enact_result = enact_verified(&block, engine, db, &parent, last_hashes); @@ -302,6 +306,8 @@ impl Client { let _import_lock = self.import_lock.lock(); let blocks = self.block_queue.write().unwrap().drain(max_blocks_to_import); + let original_best = self.chain_info().best_block_hash; + for block in blocks { let header = &block.header; @@ -357,6 +363,10 @@ impl Client { } } + if self.chain_info().best_block_hash != original_best { + self.new_chain_head(); + } + imported } @@ -403,8 +413,29 @@ impl Client { BlockId::Latest => Some(self.chain.read().unwrap().best_block_number()) } } + + /// New chain head event. + pub fn new_chain_head(&self) { + let h = self.chain.read().unwrap().best_block_hash(); + info!("NEW CHAIN HEAD: #{}: {}", self.chain.read().unwrap().best_block_number(), h); + + info!("Preparing to seal."); + let b = OpenBlock::new( + &self.engine, + self.state_db.lock(), + self.chain.read().unwrap().block_header(&h).unwrap_or_else(|| {return;}), + self.build_last_hashes(h.clone()), + x!("0037a6b811ffeb6e072da21179d11b1406371c63"), + b"Parity".to_owned() + ); + let b = b.close(); + info!("Sealed: hash={}, diff={}, number={}", b.hash(), b.block().difficulty(), b.block().number()); + *self._sealing_block.lock().unwrap() = Some(b); + } } +// TODO: need MinerService MinerIoHandler + impl BlockChainClient for Client { fn block_header(&self, id: BlockId) -> Option { let chain = self.chain.read().unwrap(); diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 6ee682544..3db0be5ff 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -131,7 +131,7 @@ impl Header { /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } /// Set the timestamp field of the header to the current time. - pub fn set_timestamp_now(&mut self) { self.timestamp = now_utc().to_timespec().sec as u64; self.note_dirty(); } + pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = max(now_utc().to_timespec().sec as u64, but_later_than + 1); self.note_dirty(); } /// Set the author field of the header. pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } } diff --git a/parity/main.rs b/parity/main.rs index 6415dfc33..ff86b1663 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -354,7 +354,6 @@ impl Default for Informant { } impl Informant { - fn format_bytes(b: usize) -> String { match binary_prefix(b as f64) { Standalone(bytes) => format!("{} bytes", bytes), From 791b0d82aa9273b63889cee6d334ca4205f8e71d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Feb 2016 14:59:10 +0100 Subject: [PATCH 266/753] Fix panic when downloading stales. --- sync/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index dd89cdbf8..6a7add27f 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -245,8 +245,8 @@ impl ChainSync { start_block_number: self.starting_block, last_imported_block_number: self.last_imported_block, highest_block_number: self.highest_block, - blocks_received: match self.last_imported_block { None => 0, Some(x) => x - self.starting_block }, - blocks_total: match self.highest_block { None => 0, Some(x) => x - self.starting_block }, + blocks_received: match self.last_imported_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, + blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), mem_used: From e20858a5dc048c06bac6d3e744979e9fc3ff1639 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Feb 2016 15:30:08 +0100 Subject: [PATCH 267/753] Compile fixes. --- ethcore/src/client.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c378fa449..a4ef970a5 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -21,7 +21,7 @@ use util::panics::*; use blockchain::{BlockChain, BlockProvider}; use views::BlockView; use error::*; -use header::{BlockNumber, Header}; +use header::{BlockNumber}; use state::State; use spec::Spec; use engine::Engine; @@ -421,15 +421,15 @@ impl Client { info!("Preparing to seal."); let b = OpenBlock::new( - &self.engine, - self.state_db.lock(), - self.chain.read().unwrap().block_header(&h).unwrap_or_else(|| {return;}), + self.engine.deref().deref(), + self.state_db.lock().unwrap().clone(), + match self.chain.read().unwrap().block_header(&h) { Some(ref x) => x, None => {return;} }, self.build_last_hashes(h.clone()), x!("0037a6b811ffeb6e072da21179d11b1406371c63"), - b"Parity".to_owned() + b"Parity".to_vec() ); let b = b.close(); - info!("Sealed: hash={}, diff={}, number={}", b.hash(), b.block().difficulty(), b.block().number()); + info!("Sealed: hash={}, diff={}, number={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); *self._sealing_block.lock().unwrap() = Some(b); } } From a1e1f4f87ce1ae37466f04cdf509b000a405b738 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Feb 2016 15:33:33 +0100 Subject: [PATCH 268/753] Disable stTransitionTest until Dimitri updates to correct number. --- ethcore/src/json_tests/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index f6b5751a7..b5f28444a 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -115,7 +115,7 @@ declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} -declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} +//declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} From 1a4e95a9dc594abf0108ed9e97ad9788a7dec65f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 29 Feb 2016 18:57:46 +0300 Subject: [PATCH 269/753] u256*u256->u512 --- util/benches/bigint.rs | 13 +++ util/src/uint.rs | 257 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index da82084b8..fc41ab628 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -74,6 +74,19 @@ fn u256_mul(b: &mut Bencher) { } +#[bench] +fn u256_full_mul(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), + |old, new| { + let U512(ref u512words) = old.full_mul(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()])); + U256([u512words[0], u512words[2], u512words[2], u512words[3]]) + }) + }); +} + + #[bench] fn u128_mul(b: &mut Bencher) { b.iter(|| { diff --git a/util/src/uint.rs b/util/src/uint.rs index 517b7a29f..bbe62e5d4 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1097,6 +1097,157 @@ construct_uint!(U512, 8); construct_uint!(U256, 4); construct_uint!(U128, 2); +impl U256 { + /// Multiplies two 256-bit integers to produce full 512-bit integer + /// No overflow possible + #[cfg(all(x64asm, target_arch="x86_64"))] + pub fn full_mul(self, other: U256) -> U512 { + let self_t: &[u64; 4] = unsafe { &mem::transmute(self) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute(other) }; + let mut result: [u64; 8] = unsafe { mem::uninitialized() }; + unsafe { + asm!(" + mov $8, %rax + mulq $12 + mov %rax, $0 + mov %rdx, $1 + + mov $8, %rax + mulq $13 + add %rax, $1 + adc $$0, %rdx + mov %rdx, $2 + + mov $8, %rax + mulq $14 + add %rax, $2 + adc $$0, %rdx + mov %rdx, $3 + + mov $8, %rax + mulq $15 + add %rax, $3 + adc $$0, %rdx + mov %rdx, $4 + + mov $9, %rax + mulq $12 + add %rax, $1 + adc %rdx, $2 + adc $$0, $3 + adc $$0, $4 + xor $5, $5 + adc $$0, $5 + xor $6, $6 + adc $$0, $6 + xor $7, $7 + adc $$0, $7 + + mov $9, %rax + mulq $13 + add %rax, $2 + adc %rdx, $3 + adc $$0, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $9, %rax + mulq $14 + add %rax, $3 + adc %rdx, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $9, %rax + mulq $15 + add %rax, $4 + adc %rdx, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $12 + add %rax, $2 + adc %rdx, $3 + adc $$0, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $13 + add %rax, $3 + adc %rdx, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $14 + add %rax, $4 + adc %rdx, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $15 + add %rax, $5 + adc %rdx, $6 + adc $$0, $7 + + mov $11, %rax + mulq $12 + add %rax, $3 + adc %rdx, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $11, %rax + mulq $13 + add %rax, $4 + adc %rdx, $5 + adc $$0, $6 + adc $$0, $7 + + mov $11, %rax + mulq $14 + add %rax, $5 + adc %rdx, $6 + adc $$0, $7 + + mov $11, %rax + mulq $15 + add %rax, $6 + adc %rdx, $7 + " + : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), + /* $3 */ "={r11}"(result[3]), /* $4 */ "={r12}"(result[4]), /* $5 */ "={r13}"(result[5]), + /* $6 */ "={r14}"(result[6]), /* $7 */ "={r15}"(result[7]) + + : /* $8 */ "m"(self_t[0]), /* $9 */ "m"(self_t[1]), /* $10 */ "m"(self_t[2]), + /* $11 */ "m"(self_t[3]), /* $12 */ "m"(other_t[0]), /* $13 */ "m"(other_t[1]), + /* $14 */ "m"(other_t[2]), /* $15 */ "m"(other_t[3]) + : "rax", "rdx" + : + ); + } + U512(result) + } + + /// Multiplies two 256-bit integers to produce full 512-bit integer + /// No overflow possible + #[cfg(not(all(x64asm, target_arch="x86_64")))] + pub fn full_mul(self, other: U256) -> U512 { + let self_512 = U512::from(self); + let other_512 = U512::from(other); + let (result, _) = self_512.overflowing_mul(other_512); + result + } +} + impl From for U512 { fn from(value: U256) -> U512 { let U256(ref arr) = value; @@ -1828,5 +1979,111 @@ mod tests { let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); assert!(overflow); } + + + #[test] + fn u256_multi_full_mul() { + let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0])); + assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([1, 0, 0, 0]).full_mul(U256([1, 0, 0, 0])); + assert_eq!(U512([1, 0, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([5, 0, 0, 0]).full_mul(U256([5, 0, 0, 0])); + assert_eq!(U512([25, 0, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([0, 5, 0, 0]).full_mul(U256([0, 5, 0, 0])); + assert_eq!(U512([0, 0, 25, 0, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 0, 4]).full_mul(U256([4, 0, 0, 0])); + assert_eq!(U512([0, 0, 0, 16, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 0, 5]).full_mul(U256([2, 0, 0, 0])); + assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 2, 0]).full_mul(U256([0, 5, 0, 0])); + assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result); + + let result = U256([0, 3, 0, 0]).full_mul(U256([0, 0, 3, 0])); + assert_eq!(U512([0, 0, 0, 9, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 8, 0]).full_mul(U256([0, 0, 6, 0])); + assert_eq!(U512([0, 0, 0, 0, 48, 0, 0, 0]), result); + + let result = U256([9, 0, 0, 0]).full_mul(U256([0, 3, 0, 0])); + assert_eq!(U512([0, 27, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX-1, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([0, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([0, 1, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, 0, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let result = U256([0, 0, 0, ::std::u64::MAX]).full_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U512([0, 0, 0, 0, 0, 0, 1, ::std::u64::MAX-1]), result); + + let result = U256([1, 0, 0, 0]).full_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U512([0, 0, 0, ::std::u64::MAX, 0, 0, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([5, 0, 0, 0])); + assert_eq!(U512([5, 10, 15, 20, 0, 0, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([0, 6, 0, 0])); + assert_eq!(U512([0, 6, 12, 18, 24, 0, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 7, 0])); + assert_eq!(U512([0, 0, 7, 14, 21, 28, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 0, 8])); + assert_eq!(U512([0, 0, 0, 8, 16, 24, 32, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([5, 6, 7, 8])); + assert_eq!(U512([5, 16, 34, 60, 61, 52, 32, 0]), result); + } } From b30f066651d480c0e7a5dbd90ed85585de5a6d6c Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 29 Feb 2016 19:15:13 +0300 Subject: [PATCH 270/753] tabified --- util/src/uint.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/util/src/uint.rs b/util/src/uint.rs index bbe62e5d4..88256d5f2 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1105,8 +1105,8 @@ impl U256 { let self_t: &[u64; 4] = unsafe { &mem::transmute(self) }; let other_t: &[u64; 4] = unsafe { &mem::transmute(other) }; let mut result: [u64; 8] = unsafe { mem::uninitialized() }; - unsafe { - asm!(" + unsafe { + asm!(" mov $8, %rax mulq $12 mov %rax, $0 @@ -1230,11 +1230,11 @@ impl U256 { : /* $8 */ "m"(self_t[0]), /* $9 */ "m"(self_t[1]), /* $10 */ "m"(self_t[2]), /* $11 */ "m"(self_t[3]), /* $12 */ "m"(other_t[0]), /* $13 */ "m"(other_t[1]), /* $14 */ "m"(other_t[2]), /* $15 */ "m"(other_t[3]) - : "rax", "rdx" - : - ); - } - U512(result) + : "rax", "rdx" + : + ); + } + U512(result) } /// Multiplies two 256-bit integers to produce full 512-bit integer From ffc5c2ea7bf5747acbbc87dca25e37943312d771 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 29 Feb 2016 19:30:13 +0100 Subject: [PATCH 271/753] eth_getwork implemented. --- Cargo.lock | 1 + ethash/src/compute.rs | 3 ++- ethash/src/lib.rs | 4 ++-- ethcore/src/client.rs | 13 +++++++------ ethcore/src/ethereum/ethash.rs | 14 ++++++++++---- rpc/Cargo.toml | 1 + rpc/src/v1/impls/eth.rs | 27 +++++++++++++++++++++++++++ util/src/misc.rs | 2 +- util/src/uint.rs | 27 +++++++++++++++++++++++++++ 9 files changed, 78 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bca236813..9c225dbbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,6 +203,7 @@ name = "ethcore-rpc" version = "0.9.99" dependencies = [ "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "ethash 0.9.99", "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index 6c311993b..eb64151d0 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -172,7 +172,8 @@ fn get_data_size(block_number: u64) -> usize { } #[inline] -fn get_seedhash(block_number: u64) -> H256 { +/// Given the `block_number`, determine the seed hash for Ethash. +pub fn get_seedhash(block_number: u64) -> H256 { let epochs = block_number / ETHASH_EPOCH_LENGTH; let mut ret: H256 = [0u8; 32]; for _ in 0..epochs { diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index e96b98b81..982f7129b 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -24,7 +24,7 @@ mod compute; use std::mem; use compute::Light; -pub use compute::{quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH}; +pub use compute::{get_seedhash, quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH}; use std::sync::{Arc, Mutex}; @@ -35,7 +35,7 @@ struct LightCache { prev: Option>, } -/// Lighy/Full cache manager +/// Light/Full cache manager. pub struct EthashManager { cache: Mutex, } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index d81507d25..f634579ad 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -195,7 +195,7 @@ pub struct Client { panic_handler: Arc, // for sealing... - _sealing_block: Mutex>, + sealing_block: Mutex>, } const HISTORY: u64 = 1000; @@ -232,7 +232,7 @@ impl Client { report: RwLock::new(Default::default()), import_lock: Mutex::new(()), panic_handler: panic_handler, - _sealing_block: Mutex::new(None), + sealing_block: Mutex::new(None), })) } @@ -417,9 +417,7 @@ impl Client { /// New chain head event. pub fn new_chain_head(&self) { let h = self.chain.read().unwrap().best_block_hash(); - info!("NEW CHAIN HEAD: #{}: {}", self.chain.read().unwrap().best_block_number(), h); - - info!("Preparing to seal."); + info!("New best block: #{}: {}", self.chain.read().unwrap().best_block_number(), h); let b = OpenBlock::new( self.engine.deref().deref(), self.state_db.lock().unwrap().clone(), @@ -430,8 +428,11 @@ impl Client { ); let b = b.close(); info!("Sealed: hash={}, diff={}, number={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); - *self._sealing_block.lock().unwrap() = Some(b); + *self.sealing_block.lock().unwrap() = Some(b); } + + /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. + pub fn sealing_block(&self) -> &Mutex> { &self.sealing_block } } // TODO: need MinerService MinerIoHandler diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 54f02524d..4f1ef1ce3 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -144,9 +144,9 @@ impl Engine for Ethash { } let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty( - &Ethash::to_ethash(header.bare_hash()), - header.nonce().low_u64(), - &Ethash::to_ethash(header.mix_hash())))); + &Ethash::to_ethash(header.bare_hash()), + header.nonce().low_u64(), + &Ethash::to_ethash(header.mix_hash()) ))); if difficulty < header.difficulty { return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty }))); } @@ -241,10 +241,16 @@ impl Ethash { target } - fn boundary_to_difficulty(boundary: &H256) -> U256 { + /// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`. + pub fn boundary_to_difficulty(boundary: &H256) -> U256 { U256::from((U512::one() << 256) / x!(U256::from(boundary.as_slice()))) } + /// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`. + pub fn difficulty_to_boundary(difficulty: &U256) -> H256 { + x!(U256::from((U512::one() << 256) / x!(difficulty))) + } + fn to_ethash(hash: H256) -> EH256 { unsafe { mem::transmute(hash) } } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b9ca9deac..c38684643 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -15,6 +15,7 @@ jsonrpc-core = "1.2" jsonrpc-http-server = "2.1" ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } +ethash = { path = "../ethash" } ethsync = { path = "../sync" } clippy = { version = "0.0.44", optional = true } rustc-serialize = "0.3" diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 00bce5437..5791b7418 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -22,7 +22,11 @@ use util::hash::*; use util::uint::*; use util::sha3::*; use ethcore::client::*; +use ethcore::block::{IsBlock}; use ethcore::views::*; +extern crate ethash; +use self::ethash::get_seedhash; +use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; @@ -209,6 +213,29 @@ impl Eth for EthClient { to_value(&logs) }) } + + fn work(&self, params: Params) -> Result { + match params { + Params::None => { + let c = take_weak!(self.client); + let u = c.sealing_block().lock().unwrap(); + match *u { + Some(ref b) => { + let current_hash = b.hash(); + let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); + let seed_hash = get_seedhash(b.block().header().number()); + to_value(&(current_hash, seed_hash, target)) + } + _ => Err(Error::invalid_params()) + } + }, + _ => Err(Error::invalid_params()) + } + } + +// fn submit_work(&self, _: Params) -> Result { rpc_unimplemented!() } + +// fn submit_hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } } /// Eth filter rpc implementation. diff --git a/util/src/misc.rs b/util/src/misc.rs index 289f1c50c..35e1f3a75 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -69,5 +69,5 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { - format!("Parity//{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) + format!("Parity//v{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) } \ No newline at end of file diff --git a/util/src/uint.rs b/util/src/uint.rs index 517b7a29f..7f2e3d3b1 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1124,6 +1124,33 @@ impl From for U256 { } } +impl<'a> From<&'a U256> for U512 { + fn from(value: &'a U256) -> U512 { + let U256(ref arr) = *value; + let mut ret = [0; 8]; + ret[0] = arr[0]; + ret[1] = arr[1]; + ret[2] = arr[2]; + ret[3] = arr[3]; + U512(ret) + } +} + +impl<'a> From<&'a U512> for U256 { + fn from(value: &'a U512) -> U256 { + let U512(ref arr) = *value; + if arr[4] | arr[5] | arr[6] | arr[7] != 0 { + panic!("Overflow"); + } + let mut ret = [0; 4]; + ret[0] = arr[0]; + ret[1] = arr[1]; + ret[2] = arr[2]; + ret[3] = arr[3]; + U256(ret) + } +} + impl From for U128 { fn from(value: U256) -> U128 { let U256(ref arr) = value; From cb4d17825bc6353461549a4a9c03424cda525cae Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 29 Feb 2016 19:49:29 +0100 Subject: [PATCH 272/753] Fixed lock order --- Cargo.toml | 1 + ethcore/src/blockchain/blockchain.rs | 78 +++++++++++++++------------- 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 25b7caa85..df3beef49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,3 +35,4 @@ name = "parity" [profile.release] debug = false +lto = false diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7339f3a1a..f30a674e6 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -433,48 +433,56 @@ impl BlockChain { batch.put(b"best", &update.info.hash).unwrap(); // These cached values must be updated atomically - let mut best_block = self.best_block.write().unwrap(); - let mut write_hashes = self.block_hashes.write().unwrap(); - let mut write_txs = self.transaction_addresses.write().unwrap(); + { + let mut best_block = self.best_block.write().unwrap(); + let mut write_hashes = self.block_hashes.write().unwrap(); + let mut write_txs = self.transaction_addresses.write().unwrap(); - // update best block - match update.info.location { - BlockLocation::Branch => (), - _ => { - *best_block = BestBlock { - hash: update.info.hash, - number: update.info.number, - total_difficulty: update.info.total_difficulty - }; + // update best block + match update.info.location { + BlockLocation::Branch => (), + _ => { + *best_block = BestBlock { + hash: update.info.hash, + number: update.info.number, + total_difficulty: update.info.total_difficulty + }; + } + } + + for (number, hash) in &update.block_hashes { + batch.put_extras(number, hash); + write_hashes.remove(number); + } + + for (hash, tx_address) in &update.transactions_addresses { + batch.put_extras(hash, tx_address); + write_txs.remove(hash); } } - for (number, hash) in &update.block_hashes { - batch.put_extras(number, hash); - write_hashes.remove(number); + { + let mut write_details = self.block_details.write().unwrap(); + for (hash, details) in update.block_details.into_iter() { + batch.put_extras(&hash, &details); + write_details.insert(hash, details); + } } - let mut write_details = self.block_details.write().unwrap(); - for (hash, details) in update.block_details.into_iter() { - batch.put_extras(&hash, &details); - write_details.insert(hash, details); + { + let mut write_receipts = self.block_receipts.write().unwrap(); + for (hash, receipt) in &update.block_receipts { + batch.put_extras(hash, receipt); + write_receipts.remove(hash); + } } - let mut write_receipts = self.block_receipts.write().unwrap(); - for (hash, receipt) in &update.block_receipts { - batch.put_extras(hash, receipt); - write_receipts.remove(hash); - } - - for (hash, tx_address) in &update.transactions_addresses { - batch.put_extras(hash, tx_address); - write_txs.remove(hash); - } - - let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); - for (bloom_hash, blocks_bloom) in &update.blocks_blooms { - batch.put_extras(bloom_hash, blocks_bloom); - write_blocks_blooms.remove(bloom_hash); + { + let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); + for (bloom_hash, blocks_bloom) in &update.blocks_blooms { + batch.put_extras(bloom_hash, blocks_bloom); + write_blocks_blooms.remove(bloom_hash); + } } // update extras database @@ -580,7 +588,7 @@ impl BlockChain { /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); - let transaction_hashes = block.transaction_hashes(); + let transaction_hashes = block.transaction_hashes(); transaction_hashes.into_iter() .enumerate() From 8920bea2418a01f46cd06e2da22e2920dc960af9 Mon Sep 17 00:00:00 2001 From: Wojciech Langiewicz Date: Mon, 29 Feb 2016 21:14:38 +0100 Subject: [PATCH 273/753] ignore out directory --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 58b1895c6..3226ea5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ # jetbrains ide stuff .idea *.iml + +# Build artifacts +out/ From d0129ff67b5e69436df88a6758e81d880e924a23 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 29 Feb 2016 21:15:39 +0100 Subject: [PATCH 274/753] Fixed cache memory leak --- ethcore/src/blockchain/blockchain.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index f30a674e6..23e9aaac9 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -465,6 +465,7 @@ impl BlockChain { let mut write_details = self.block_details.write().unwrap(); for (hash, details) in update.block_details.into_iter() { batch.put_extras(&hash, &details); + self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); write_details.insert(hash, details); } } @@ -769,6 +770,14 @@ impl BlockChain { // TODO: handle block_hashes properly. block_hashes.clear(); + + blocks.shrink_to_fit(); + block_details.shrink_to_fit(); + block_hashes.shrink_to_fit(); + transaction_addresses.shrink_to_fit(); + block_logs.shrink_to_fit(); + blocks_blooms.shrink_to_fit(); + block_receipts.shrink_to_fit(); } if self.cache_size().total() < self.max_cache_size.load(AtomicOrder::Relaxed) { break; } } From 4bf77c03f526ce58e6a65f2a221e6d9156db8a5e Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Thu, 18 Feb 2016 19:30:58 +0100 Subject: [PATCH 275/753] Moving Table to utils. Fixing couple of small things --- util/src/lib.rs | 1 + util/src/table.rs | 122 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 util/src/table.rs diff --git a/util/src/lib.rs b/util/src/lib.rs index 2a47eb438..ea60418db 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -144,6 +144,7 @@ pub mod network; pub mod log; pub mod panics; pub mod keys; +pub mod table; pub use common::*; pub use misc::*; diff --git a/util/src/table.rs b/util/src/table.rs new file mode 100644 index 000000000..572d81f84 --- /dev/null +++ b/util/src/table.rs @@ -0,0 +1,122 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! A collection associating pair of keys (row and column) with a single value. + +use std::hash::Hash; +use std::collections::HashMap; + +/// Structure to hold double-indexed values +/// +/// You can obviously use `HashMap<(Row,Col), Val>`, but this structure gives +/// you better access to all `Columns` in Specific `Row`. Namely you can get sub-hashmap +/// `HashMap` for specific `Row` +pub struct Table + where Row: Eq + Hash + Clone, + Col: Eq + Hash { + map: HashMap>, +} + +impl Table + where Row: Eq + Hash + Clone, + Col: Eq + Hash { + /// Creates new Table + pub fn new() -> Table { + Table { + map: HashMap::new(), + } + } + + /// Removes all elements from this Table + pub fn clear(&mut self) { + self.map.clear(); + } + + /// Returns length of the Table (number of (row, col, val) tuples) + pub fn len(&self) -> usize { + self.map.iter().fold(0, |acc, (_k, v)| acc + v.len()) + } + + /// Check if there is any element in this Table + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get mutable reference for single Table row. + pub fn get_row_mut(&mut self, row: &Row) -> Option<&mut HashMap> { + self.map.get_mut(row) + } + + /// Checks if row is defined for that table (note that even if defined it might be empty) + pub fn has_row(&self, row: &Row) -> bool { + self.map.contains_key(row) + } + + /// Get immutable reference for single row in this Table + pub fn get_row(&self, row: &Row) -> Option<&HashMap> { + self.map.get(row) + } + + /// Get element in cell described by `(row, col)` + pub fn get(&self, row: &Row, col: &Col) -> Option<&Val> { + self.map.get(row).and_then(|r| r.get(col)) + } + + /// Remove value from specific cell + /// + /// It will remove the row if it's the last value in it + pub fn remove(&mut self, row: &Row, col: &Col) -> Option { + let (val, is_empty) = { + let row_map = self.map.get_mut(row); + if let None = row_map { + return None; + } + let mut row_map = row_map.unwrap(); + let val = row_map.remove(col); + (val, row_map.is_empty()) + }; + // Clean row + if is_empty { + self.map.remove(row); + } + val + } + + /// Remove given row from Table if there are no values defined in it + /// + /// When using `#get_row_mut` it may happen that all values from some row are drained. + /// Table however will not be aware that row is empty. + /// You can use this method to explicitly remove row entry from the Table. + pub fn clear_if_empty(&mut self, row: &Row) { + let is_empty = self.map.get(row).map_or(false, |m| m.is_empty()); + if is_empty { + self.map.remove(row); + } + } + + /// Inserts new value to specified cell + /// + /// Returns previous value (if any) + pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option { + if !self.map.contains_key(&row) { + let m = HashMap::new(); + self.map.insert(row.clone(), m); + } + + let mut columns = self.map.get_mut(&row).unwrap(); + columns.insert(col, val) + } +} From d0125f3ff5ad964644080eea646f769766e952f7 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 1 Mar 2016 00:21:15 +0300 Subject: [PATCH 276/753] uint to separated crate --- Cargo.lock | 13 ++++++ ethcore/src/action_params.rs | 4 +- ethcore/src/blockchain/best_block.rs | 3 +- ethcore/src/blockchain/block_info.rs | 3 +- ethcore/src/blockchain/bloom_indexer.rs | 4 +- ethcore/src/blockchain/tree_route.rs | 2 +- ethcore/src/blockchain/update.rs | 2 +- ethcore/src/evm/ext.rs | 24 +++++----- ethcore/src/state.rs | 3 +- rpc/src/v1/impls/eth.rs | 3 +- rpc/src/v1/types/block.rs | 6 +-- rpc/src/v1/types/filter.rs | 2 +- rpc/src/v1/types/log.rs | 8 ++-- rpc/src/v1/types/sync.rs | 2 +- rpc/src/v1/types/transaction.rs | 3 +- util/Cargo.toml | 1 + util/bigint/Cargo.toml | 23 ++++++++++ util/bigint/build.rs | 25 ++++++++++ util/bigint/src/lib.rs | 23 ++++++++++ util/{ => bigint}/src/uint.rs | 61 +++++++++++++------------ util/build.rs | 6 --- util/src/common.rs | 4 +- util/src/crypto.rs | 5 +- util/src/from_json.rs | 18 ++++++++ util/src/hash.rs | 6 +-- util/src/heapsizeof.rs | 3 +- util/src/lib.rs | 4 +- util/src/numbers.rs | 20 ++++++++ util/src/rlp/bytes.rs | 2 +- util/src/rlp/tests.rs | 2 +- 30 files changed, 194 insertions(+), 91 deletions(-) create mode 100644 util/bigint/Cargo.toml create mode 100644 util/bigint/build.rs create mode 100644 util/bigint/src/lib.rs rename util/{ => bigint}/src/uint.rs (98%) create mode 100644 util/src/numbers.rs diff --git a/Cargo.lock b/Cargo.lock index bca236813..9ce1c4372 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,18 @@ dependencies = [ "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bigint" +version = "0.1.0" +dependencies = [ + "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.3.3" @@ -220,6 +232,7 @@ name = "ethcore-util" version = "0.9.99" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "bigint 0.1.0", "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/src/action_params.rs b/ethcore/src/action_params.rs index 9e2d72c73..fa40d30a0 100644 --- a/ethcore/src/action_params.rs +++ b/ethcore/src/action_params.rs @@ -15,9 +15,7 @@ // along with Parity. If not, see . //! Evm input params. -use util::hash::*; -use util::uint::*; -use util::bytes::*; +use common::*; /// Transaction value #[derive(Clone, Debug)] diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index cbb219617..8dc67ed09 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::H256; -use util::uint::U256; +use util::common::{U256,H256}; use header::BlockNumber; /// Best block info. diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index 98dac648d..fbfc0fd96 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::H256; -use util::uint::U256; +use util::common::{U256,H256}; use header::BlockNumber; /// Brief info about inserted block. diff --git a/ethcore/src/blockchain/bloom_indexer.rs b/ethcore/src/blockchain/bloom_indexer.rs index 74c679ba8..51a4f61bf 100644 --- a/ethcore/src/blockchain/bloom_indexer.rs +++ b/ethcore/src/blockchain/bloom_indexer.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::H256; +use util::common::H256; use chainfilter::BloomIndex; /// Represents location of block bloom in extras database. @@ -44,7 +44,7 @@ impl BloomIndexer { /// Calculates bloom's position in database. pub fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { use std::{mem, ptr}; - + let hash = unsafe { let mut hash: H256 = mem::zeroed(); ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/blockchain/tree_route.rs index 1bd0e6f75..4532236aa 100644 --- a/ethcore/src/blockchain/tree_route.rs +++ b/ethcore/src/blockchain/tree_route.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::H256; +use util::common::H256; /// Represents a tree route between `from` block and `to` block: #[derive(Debug)] diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index f8ca06e66..526efac73 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use util::hash::H256; +use util::common::H256; use header::BlockNumber; use blockchain::block_info::BlockInfo; use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms}; diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index ae4cff3be..f4172f10a 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -16,9 +16,7 @@ //! Interface for Evm externalities. -use common::Bytes; -use util::hash::*; -use util::uint::*; +use util::common::*; use evm::{Schedule, Error}; use env_info::*; @@ -60,22 +58,22 @@ pub trait Ext { fn blockhash(&self, number: &U256) -> H256; /// Creates new contract. - /// + /// /// Returns gas_left and contract address if contract creation was succesfull. fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult; /// Message call. - /// + /// /// Returns Err, if we run out of gas. - /// Otherwise returns call_result which contains gas left + /// Otherwise returns call_result which contains gas left /// and true if subcall was successfull. - fn call(&mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, + fn call(&mut self, + gas: &U256, + sender_address: &Address, + receive_address: &Address, value: Option, - data: &[u8], - code_address: &Address, + data: &[u8], + code_address: &Address, output: &mut [u8]) -> MessageCallResult; /// Returns code at given address @@ -99,7 +97,7 @@ pub trait Ext { fn env_info(&self) -> &EnvInfo; /// Returns current depth of execution. - /// + /// /// If contract A calls contract B, and contract B calls C, /// then A depth is 0, B is 1, C is 2 and so on. fn depth(&self) -> usize; diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 8bbf317c1..83b77ece0 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -335,10 +335,9 @@ impl fmt::Debug for State { mod tests { use super::*; -use util::hash::*; +use util::common::*; use util::trie::*; use util::rlp::*; -use util::uint::*; use account::*; use tests::helpers::*; use devtools::*; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 00bce5437..0dd5714d2 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -18,8 +18,7 @@ use std::sync::{Arc, Weak}; use ethsync::{EthSync, SyncState}; use jsonrpc_core::*; -use util::hash::*; -use util::uint::*; +use util::numbers::*; use util::sha3::*; use ethcore::client::*; use ethcore::views::*; diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index b92111bcb..2457efcf8 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -15,8 +15,7 @@ // along with Parity. If not, see . use serde::{Serialize, Serializer}; -use util::hash::*; -use util::uint::*; +use util::numbers::*; use v1::types::{Bytes, Transaction, OptionalValue}; #[derive(Debug)] @@ -71,8 +70,7 @@ pub struct Block { #[cfg(test)] mod tests { use serde_json; - use util::hash::*; - use util::uint::*; + use util::numbers::*; use v1::types::{Transaction, Bytes, OptionalValue}; use super::*; diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index 01d322cce..16a08764b 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -17,7 +17,7 @@ use serde::{Deserialize, Deserializer, Error}; use serde_json::value; use jsonrpc_core::Value; -use util::hash::*; +use util::numbers::*; use v1::types::BlockNumber; use ethcore::filter::Filter as EthFilter; use ethcore::client::BlockId; diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 0629c5534..0f5fdee15 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::*; -use util::uint::*; +use util::numbers::*; use ethcore::log_entry::LocalizedLogEntry; use v1::types::Bytes; @@ -55,8 +54,7 @@ impl From for Log { mod tests { use serde_json; use std::str::FromStr; - use util::hash::*; - use util::uint::*; + use util::numbers::*; use v1::types::{Bytes, Log}; #[test] @@ -66,7 +64,7 @@ mod tests { let log = Log { address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), topics: vec![ - H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() ], data: Bytes::new(vec![]), diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index b5568acda..c0e480140 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use serde::{Serialize, Serializer}; -use util::uint::*; +use util::numbers::*; #[derive(Default, Debug, Serialize, PartialEq)] pub struct SyncInfo { diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 0e9256ada..232cf0bf3 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::*; -use util::uint::*; +use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; diff --git a/util/Cargo.toml b/util/Cargo.toml index b7eafd905..0c7df3f40 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -35,6 +35,7 @@ ethcore-devtools = { path = "../devtools" } libc = "0.2.7" vergen = "0.1" target_info = "0.1" +bigint = { path = "bigint" } [features] default = [] diff --git a/util/bigint/Cargo.toml b/util/bigint/Cargo.toml new file mode 100644 index 000000000..377391eeb --- /dev/null +++ b/util/bigint/Cargo.toml @@ -0,0 +1,23 @@ +[package] +description = "Rust-assembler implementation of big integers arithmetic" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "bigint" +version = "0.1.0" +authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +rustc_version = "0.1" + +[dependencies] +rustc-serialize = "0.3" +arrayvec = "0.3" +rand = "0.3.12" +serde = "0.7.0" +clippy = { version = "0.0.44", optional = true } +heapsize = "0.3" + +[features] +x64asm_arithmetic=[] +rust_arithmetic=[] diff --git a/util/bigint/build.rs b/util/bigint/build.rs new file mode 100644 index 000000000..248823229 --- /dev/null +++ b/util/bigint/build.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=asm_available"); + } +} diff --git a/util/bigint/src/lib.rs b/util/bigint/src/lib.rs new file mode 100644 index 000000000..149878538 --- /dev/null +++ b/util/bigint/src/lib.rs @@ -0,0 +1,23 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#![cfg_attr(asm_available, feature(asm))] + +extern crate rustc_serialize; +extern crate serde; +#[macro_use] extern crate heapsize; + +pub mod uint; diff --git a/util/src/uint.rs b/util/bigint/src/uint.rs similarity index 98% rename from util/src/uint.rs rename to util/bigint/src/uint.rs index 88256d5f2..4cc0dfc0e 100644 --- a/util/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -36,10 +36,26 @@ //! The functions here are designed to be fast. //! -use standard::*; -use from_json::*; -use rustc_serialize::hex::ToHex; +use std::fmt; +use std::cmp; + +use std::mem; +use std::ops; +use std::slice; +use std::result; +use std::option; +use std::str::{FromStr}; +use std::convert::From; +use std::hash::{Hash, Hasher}; +use std::ops::*; +use std::cmp::*; +use std::collections::*; + use serde; +use rustc_serialize::json::Json; +use rustc_serialize::base64::FromBase64; +use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; + macro_rules! impl_map_from { ($thing:ident, $from:ty, $to:ty) => { @@ -51,7 +67,7 @@ macro_rules! impl_map_from { } } -#[cfg(not(all(x64asm, target_arch="x86_64")))] +#[cfg(not(all(asm_available, target_arch="x86_64")))] macro_rules! uint_overflowing_add { ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) @@ -88,8 +104,7 @@ macro_rules! uint_overflowing_add_reg { }) } - -#[cfg(all(x64asm, target_arch="x86_64"))] +#[cfg(all(asm_available, target_arch="x86_64"))] macro_rules! uint_overflowing_add { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -165,7 +180,7 @@ macro_rules! uint_overflowing_add { ) } -#[cfg(not(all(x64asm, target_arch="x86_64")))] +#[cfg(not(all(asm_available, target_arch="x86_64")))] macro_rules! uint_overflowing_sub { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let res = overflowing!((!$other).overflowing_add(From::from(1u64))); @@ -174,7 +189,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(x64asm, target_arch="x86_64"))] +#[cfg(all(asm_available, target_arch="x86_64"))] macro_rules! uint_overflowing_sub { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -250,7 +265,7 @@ macro_rules! uint_overflowing_sub { }) } -#[cfg(all(x64asm, target_arch="x86_64"))] +#[cfg(all(asm_available, target_arch="x86_64"))] macro_rules! uint_overflowing_mul { (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut result: [u64; 4] = unsafe { mem::uninitialized() }; @@ -370,7 +385,7 @@ macro_rules! uint_overflowing_mul { ) } -#[cfg(not(all(x64asm, target_arch="x86_64")))] +#[cfg(not(all(asm_available, target_arch="x86_64")))] macro_rules! uint_overflowing_mul { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) @@ -381,7 +396,6 @@ macro_rules! uint_overflowing_mul_reg { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut res = $name::from(0u64); let mut overflow = false; - // TODO: be more efficient about this for i in 0..(2 * $n_words) { let v = overflowing!($self_expr.overflowing_mul_u32(($other >> (32 * i)).low_u32()), overflow); let res2 = overflowing!(v.overflowing_shl(32 * i as u32), overflow); @@ -416,7 +430,7 @@ macro_rules! panic_on_overflow { } /// Large, fixed-length unsigned integer type. -pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { +pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { /// Returns new instance equalling zero. fn zero() -> Self; @@ -779,22 +793,6 @@ macro_rules! construct_uint { } } - impl FromJson for $name { - fn from_json(json: &Json) -> Self { - match *json { - Json::String(ref s) => { - if s.len() >= 2 && &s[0..2] == "0x" { - FromStr::from_str(&s[2..]).unwrap_or_else(|_| Default::default()) - } else { - Uint::from_dec_str(s).unwrap_or_else(|_| Default::default()) - } - }, - Json::U64(u) => From::from(u), - Json::I64(i) => From::from(i as u64), - _ => Uint::zero(), - } - } - } impl_map_from!($name, u8, u64); impl_map_from!($name, u16, u64); @@ -1100,7 +1098,7 @@ construct_uint!(U128, 2); impl U256 { /// Multiplies two 256-bit integers to produce full 512-bit integer /// No overflow possible - #[cfg(all(x64asm, target_arch="x86_64"))] + #[cfg(all(asm_available, target_arch="x86_64"))] pub fn full_mul(self, other: U256) -> U512 { let self_t: &[u64; 4] = unsafe { &mem::transmute(self) }; let other_t: &[u64; 4] = unsafe { &mem::transmute(other) }; @@ -1239,7 +1237,7 @@ impl U256 { /// Multiplies two 256-bit integers to produce full 512-bit integer /// No overflow possible - #[cfg(not(all(x64asm, target_arch="x86_64")))] + #[cfg(not(all(asm_available, target_arch="x86_64")))] pub fn full_mul(self, other: U256) -> U512 { let self_512 = U512::from(self); let other_512 = U512::from(other); @@ -1338,6 +1336,9 @@ pub const ZERO_U256: U256 = U256([0x00u64; 4]); /// Constant value of `U256::one()` that can be used for a reference saving an additional instance creation. pub const ONE_U256: U256 = U256([0x01u64, 0x00u64, 0x00u64, 0x00u64]); + +known_heap_size!(0, U128, U256); + #[cfg(test)] mod tests { use uint::{Uint, U128, U256, U512}; diff --git a/util/build.rs b/util/build.rs index 2b581642b..eed080e29 100644 --- a/util/build.rs +++ b/util/build.rs @@ -1,13 +1,7 @@ extern crate vergen; -extern crate rustc_version; use vergen::*; -use rustc_version::{version_meta, Channel}; fn main() { vergen(OutputFns::all()).unwrap(); - - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=x64asm"); - } } diff --git a/util/src/common.rs b/util/src/common.rs index 0816b72e4..a96bf5444 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -19,12 +19,12 @@ pub use standard::*; pub use from_json::*; pub use error::*; -pub use hash::*; -pub use uint::*; pub use bytes::*; pub use vector::*; +pub use numbers::*; pub use sha3::*; + #[macro_export] macro_rules! map { ( $( $x:expr => $y:expr ),* ) => { diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 2d5516b6f..48d98708b 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -16,9 +16,8 @@ //! Ethcore crypto. -use hash::*; +use numbers::*; use bytes::*; -use uint::*; use secp256k1::{key, Secp256k1}; use rand::os::OsRng; @@ -152,7 +151,7 @@ impl KeyPair { /// EC functions pub mod ec { use hash::*; - use uint::*; + use bigint::uint::*; use standard::*; use crypto::*; use crypto::{self}; diff --git a/util/src/from_json.rs b/util/src/from_json.rs index 7d977afc9..a598ed961 100644 --- a/util/src/from_json.rs +++ b/util/src/from_json.rs @@ -17,6 +17,7 @@ //! Coversion from json. use standard::*; +use bigint::uint::*; #[macro_export] macro_rules! xjson { @@ -30,3 +31,20 @@ pub trait FromJson { /// Convert a JSON value to an instance of this type. fn from_json(json: &Json) -> Self; } + +impl FromJson for U256 { + fn from_json(json: &Json) -> Self { + match *json { + Json::String(ref s) => { + if s.len() >= 2 && &s[0..2] == "0x" { + FromStr::from_str(&s[2..]).unwrap_or_else(|_| Default::default()) + } else { + Uint::from_dec_str(s).unwrap_or_else(|_| Default::default()) + } + }, + Json::U64(u) => From::from(u), + Json::I64(i) => From::from(i as u64), + _ => Uint::zero(), + } + } +} diff --git a/util/src/hash.rs b/util/src/hash.rs index 88c57371e..42fdff663 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -23,7 +23,7 @@ use rand::Rng; use rand::os::OsRng; use bytes::{BytesConvertable,Populatable}; use from_json::*; -use uint::{Uint, U256}; +use bigint::uint::{Uint, U256}; use rustc_serialize::hex::ToHex; use serde; @@ -595,7 +595,7 @@ pub fn h256_from_hex(s: &str) -> H256 { /// Convert `n` to an `H256`, setting the rightmost 8 bytes. pub fn h256_from_u64(n: u64) -> H256 { - use uint::U256; + use bigint::uint::U256; H256::from(&U256::from(n)) } @@ -631,7 +631,7 @@ pub static ZERO_H256: H256 = H256([0x00; 32]); #[cfg(test)] mod tests { use hash::*; - use uint::*; + use bigint::uint::*; use std::str::FromStr; #[test] diff --git a/util/src/heapsizeof.rs b/util/src/heapsizeof.rs index d7c8124cd..feb679a0b 100644 --- a/util/src/heapsizeof.rs +++ b/util/src/heapsizeof.rs @@ -16,8 +16,7 @@ //! Calculates heapsize of util types. -use uint::*; use hash::*; known_heap_size!(0, H32, H64, H128, Address, H256, H264, H512, H520, H1024, H2048); -known_heap_size!(0, U128, U256); + diff --git a/util/src/lib.rs b/util/src/lib.rs index 2a47eb438..dd3ef102b 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -16,7 +16,6 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(x64asm, feature(asm))] #![cfg_attr(feature="dev", plugin(clippy))] // Clippy settings @@ -111,15 +110,16 @@ extern crate libc; extern crate rustc_version; extern crate target_info; extern crate vergen; +extern crate bigint; pub mod standard; #[macro_use] pub mod from_json; #[macro_use] pub mod common; +pub mod numbers; pub mod error; pub mod hash; -pub mod uint; pub mod bytes; pub mod rlp; pub mod misc; diff --git a/util/src/numbers.rs b/util/src/numbers.rs new file mode 100644 index 000000000..b79338fc1 --- /dev/null +++ b/util/src/numbers.rs @@ -0,0 +1,20 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Utils number types. + +pub use hash::*; +pub use bigint::uint::*; diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs index 2ff6281cc..e8bfa57b0 100644 --- a/util/src/rlp/bytes.rs +++ b/util/src/rlp/bytes.rs @@ -21,7 +21,7 @@ use std::mem; use std::fmt; use std::cmp::Ordering; use std::error::Error as StdError; -use uint::{Uint, U128, U256}; +use bigint::uint::{Uint, U128, U256}; use hash::FixedHash; use elastic_array::*; diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index eb2039103..a92dd5c4a 100644 --- a/util/src/rlp/tests.rs +++ b/util/src/rlp/tests.rs @@ -21,7 +21,7 @@ use std::{fmt, cmp}; use std::str::FromStr; use rlp; use rlp::{UntrustedRlp, RlpStream, View, Stream, DecoderError}; -use uint::U256; +use bigint::uint::U256; #[test] fn rlp_at() { From 16038d9555ee8b48b691e26a0be968df26bcac60 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 1 Mar 2016 00:23:49 +0300 Subject: [PATCH 277/753] hash&uint -> numbers --- util/src/crypto.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 48d98708b..66e9f2edb 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -150,8 +150,7 @@ impl KeyPair { /// EC functions pub mod ec { - use hash::*; - use bigint::uint::*; + use numbers::*; use standard::*; use crypto::*; use crypto::{self}; From f528d8c50a37a04d3b1b7fa24dda9c051db3d0d1 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 1 Mar 2016 00:44:45 +0300 Subject: [PATCH 278/753] common -> numbers (as most narrow) --- ethcore/src/blockchain/best_block.rs | 2 +- ethcore/src/blockchain/block_info.rs | 2 +- ethcore/src/blockchain/bloom_indexer.rs | 2 +- ethcore/src/blockchain/tree_route.rs | 2 +- ethcore/src/blockchain/update.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs index 8dc67ed09..00c092713 100644 --- a/ethcore/src/blockchain/best_block.rs +++ b/ethcore/src/blockchain/best_block.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::common::{U256,H256}; +use util::numbers::{U256,H256}; use header::BlockNumber; /// Best block info. diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index fbfc0fd96..ce639bfed 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::common::{U256,H256}; +use util::numbers::{U256,H256}; use header::BlockNumber; /// Brief info about inserted block. diff --git a/ethcore/src/blockchain/bloom_indexer.rs b/ethcore/src/blockchain/bloom_indexer.rs index 51a4f61bf..a672a5445 100644 --- a/ethcore/src/blockchain/bloom_indexer.rs +++ b/ethcore/src/blockchain/bloom_indexer.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::common::H256; +use util::numbers::H256; use chainfilter::BloomIndex; /// Represents location of block bloom in extras database. diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/blockchain/tree_route.rs index 4532236aa..3c4906449 100644 --- a/ethcore/src/blockchain/tree_route.rs +++ b/ethcore/src/blockchain/tree_route.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::common::H256; +use util::numbers::H256; /// Represents a tree route between `from` block and `to` block: #[derive(Debug)] diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 526efac73..6be2647d3 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use util::common::H256; +use util::numbers::H256; use header::BlockNumber; use blockchain::block_info::BlockInfo; use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms}; From f2fdb8b69ba90a5593f60ba1fa3018f77121e60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 29 Feb 2016 22:56:56 +0100 Subject: [PATCH 279/753] Table tests --- util/src/table.rs | 138 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/util/src/table.rs b/util/src/table.rs index 572d81f84..525002dc3 100644 --- a/util/src/table.rs +++ b/util/src/table.rs @@ -120,3 +120,141 @@ impl Table columns.insert(col, val) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn should_create_empty_table() { + // when + let table : Table = Table::new(); + + // then + assert!(table.is_empty()); + assert_eq!(table.len(), 0); + } + + #[test] + fn should_insert_elements_and_return_previous_if_any() { + // given + let mut table = Table::new(); + + // when + let r1 = table.insert(5, 4, true); + let r2 = table.insert(10, 4, true); + let r3 = table.insert(10, 10, true); + let r4 = table.insert(10, 10, false); + + // then + assert!(r1.is_none()); + assert!(r2.is_none()); + assert!(r3.is_none()); + assert!(r4.is_some()); + assert!(!table.is_empty()); + assert_eq!(r4.unwrap(), true); + assert_eq!(table.len(), 3); + } + + #[test] + fn should_remove_element() { + // given + let mut table = Table::new(); + table.insert(5, 4, true); + assert!(!table.is_empty()); + assert_eq!(table.len(), 1); + + // when + let r = table.remove(&5, &4); + + // then + assert!(table.is_empty()); + assert_eq!(table.len() ,0); + assert_eq!(r.unwrap(), true); + } + + #[test] + fn should_return_none_if_trying_to_remove_non_existing_element() { + // given + let mut table : Table = Table::new(); + assert!(table.is_empty()); + + // when + let r = table.remove(&5, &4); + + // then + assert!(r.is_none()); + } + + #[test] + fn should_clear_row_if_removing_last_element() { + // given + let mut table = Table::new(); + table.insert(5, 4, true); + assert!(table.has_row(&5)); + + // when + let r = table.remove(&5, &4); + + // then + assert!(r.is_some()); + assert!(!table.has_row(&5)); + } + + #[test] + fn should_return_element_given_row_and_col() { + // given + let mut table = Table::new(); + table.insert(1551, 1234, 123); + + // when + let r1 = table.get(&1551, &1234); + let r2 = table.get(&5, &4); + + // then + assert!(r1.is_some()); + assert!(r2.is_none()); + assert_eq!(r1.unwrap(), &123); + } + + #[test] + fn should_clear_table() { + // given + let mut table = Table::new(); + table.insert(1, 1, true); + table.insert(1, 2, false); + table.insert(2, 2, false); + assert_eq!(table.len(), 3); + + // when + table.clear(); + + // then + assert!(table.is_empty()); + assert_eq!(table.len(), 0); + assert_eq!(table.has_row(&1), false); + assert_eq!(table.has_row(&2), false); + } + + #[test] + fn should_return_mutable_row() { + // given + let mut table = Table::new(); + table.insert(1, 1, true); + table.insert(1, 2, false); + table.insert(2, 2, false); + + // when + { + let mut row = table.get_row_mut(&1).unwrap(); + row.remove(&1); + row.remove(&2); + } + assert!(table.has_row(&1)); + table.clear_if_empty(&1); + + // then + assert!(!table.has_row(&1)); + assert_eq!(table.len(), 1); + } +} From 212aac42bdb820f9a030279af9a4b0439d424cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 29 Feb 2016 23:09:51 +0100 Subject: [PATCH 280/753] Removing clippy warnings --- util/src/keys/geth_import.rs | 16 ++++++++-------- util/src/network/host.rs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/util/src/keys/geth_import.rs b/util/src/keys/geth_import.rs index 2ee3c987c..cdbd9b213 100644 --- a/util/src/keys/geth_import.rs +++ b/util/src/keys/geth_import.rs @@ -46,14 +46,14 @@ pub fn enumerate_geth_keys(path: &Path) -> Result, io::Er #[derive(Debug)] pub enum ImportError { /// Io error reading geth file - IoError(io::Error), + Io(io::Error), /// format error - FormatError, + Format, } impl From for ImportError { fn from (err: io::Error) -> ImportError { - ImportError::IoError(err) + ImportError::Io(err) } } @@ -65,15 +65,15 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) let mut json_result = Json::from_str(&buf); let mut json = match json_result { - Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::FormatError)), - Err(_) => { return Err(ImportError::FormatError); } + Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::Format)), + Err(_) => { return Err(ImportError::Format); } }; - let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::FormatError)).clone(); + let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::Format)).clone(); json.insert("crypto".to_owned(), Json::Object(crypto_object)); json.remove("Crypto"); match KeyFileContent::load(&Json::Object(json.clone())) { Ok(key_file) => try!(secret_store.import_key(key_file)), - Err(_) => { return Err(ImportError::FormatError); } + Err(_) => { return Err(ImportError::Format); } }; Ok(()) } @@ -82,7 +82,7 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> { use std::path::PathBuf; let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory)); - for &(ref address, ref file_path) in geth_files.iter() { + for &(ref address, ref file_path) in &geth_files { let mut path = PathBuf::new(); path.push(geth_keyfiles_directory); path.push(file_path); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index f54c85855..42e8ff93d 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -376,7 +376,7 @@ impl Host where Message: Send + Sync + Clone { let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; self.pinned_nodes.push(n.id.clone()); self.nodes.write().unwrap().add_node(n); - if let &mut Some(ref mut discovery) = self.discovery.lock().unwrap().deref_mut() { + if let Some(ref mut discovery) = *self.discovery.lock().unwrap().deref_mut() { discovery.add_node(entry); } } @@ -418,7 +418,7 @@ impl Host where Message: Send + Sync + Clone { } Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port } }; - + // Setup the server socket *tcp_listener = Some(TcpListener::bind(&listen_address).unwrap()); self.info.write().unwrap().public_endpoint = public_endpoint.clone(); @@ -697,7 +697,7 @@ impl Host where Message: Send + Sync + Clone { let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); let mut discovery = self.discovery.lock().unwrap(); - if let &mut Some(ref mut discovery) = discovery.deref_mut() { + if let Some(ref mut discovery) = *discovery.deref_mut() { discovery.add_node(entry); } } From 82a528961bf3f69d50b11fb9f26fc8ec83c97237 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 1 Mar 2016 01:13:00 +0300 Subject: [PATCH 281/753] remove line --- util/src/common.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/util/src/common.rs b/util/src/common.rs index a96bf5444..b2a06c4b9 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -24,7 +24,6 @@ pub use vector::*; pub use numbers::*; pub use sha3::*; - #[macro_export] macro_rules! map { ( $( $x:expr => $y:expr ),* ) => { From 8c60eaa54864b8f7b85faf310430ca7eb657ccb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 29 Feb 2016 23:43:48 +0100 Subject: [PATCH 282/753] Unused variable --- sync/src/tests/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 63a0b88bb..b788e0c2a 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -117,7 +117,7 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn logs(&self, filter: Filter) -> Vec { + fn logs(&self, _filter: Filter) -> Vec { unimplemented!(); } From 2f3b0c9d1cbc5316fb6655049196956c189cc2df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 29 Feb 2016 23:57:02 +0100 Subject: [PATCH 283/753] Removing get_ prefix --- util/src/table.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/src/table.rs b/util/src/table.rs index 525002dc3..44b0282e1 100644 --- a/util/src/table.rs +++ b/util/src/table.rs @@ -56,7 +56,7 @@ impl Table } /// Get mutable reference for single Table row. - pub fn get_row_mut(&mut self, row: &Row) -> Option<&mut HashMap> { + pub fn row_mut(&mut self, row: &Row) -> Option<&mut HashMap> { self.map.get_mut(row) } @@ -66,7 +66,7 @@ impl Table } /// Get immutable reference for single row in this Table - pub fn get_row(&self, row: &Row) -> Option<&HashMap> { + pub fn row(&self, row: &Row) -> Option<&HashMap> { self.map.get(row) } @@ -97,7 +97,7 @@ impl Table /// Remove given row from Table if there are no values defined in it /// - /// When using `#get_row_mut` it may happen that all values from some row are drained. + /// When using `#row_mut` it may happen that all values from some row are drained. /// Table however will not be aware that row is empty. /// You can use this method to explicitly remove row entry from the Table. pub fn clear_if_empty(&mut self, row: &Row) { @@ -246,7 +246,7 @@ mod test { // when { - let mut row = table.get_row_mut(&1).unwrap(); + let mut row = table.row_mut(&1).unwrap(); row.remove(&1); row.remove(&2); } From ed6a35f61842bbd5714d8f57a5928ed56cdb3ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 1 Mar 2016 00:00:52 +0100 Subject: [PATCH 284/753] More idiomatic implementations --- util/src/table.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/util/src/table.rs b/util/src/table.rs index 44b0282e1..dd42f847a 100644 --- a/util/src/table.rs +++ b/util/src/table.rs @@ -47,7 +47,7 @@ impl Table /// Returns length of the Table (number of (row, col, val) tuples) pub fn len(&self) -> usize { - self.map.iter().fold(0, |acc, (_k, v)| acc + v.len()) + self.map.values().fold(0, |acc, v| acc + v.len()) } /// Check if there is any element in this Table @@ -111,13 +111,7 @@ impl Table /// /// Returns previous value (if any) pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option { - if !self.map.contains_key(&row) { - let m = HashMap::new(); - self.map.insert(row.clone(), m); - } - - let mut columns = self.map.get_mut(&row).unwrap(); - columns.insert(col, val) + self.map.entry(row).or_insert_with(|| HashMap::new()).insert(col, val) } } From 394e9c679bfb0e49c51a67b05001043c648a76cc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 00:02:48 +0100 Subject: [PATCH 285/753] Reorganised ImportError to be a type of Errpr (rather than vice-versa). Added support for eth_submitWork. --- ethcore/src/block.rs | 16 ++++++++++++-- ethcore/src/block_queue.rs | 24 ++++++++++---------- ethcore/src/client.rs | 40 +++++++++++++++++++++++++++------- ethcore/src/engine.rs | 2 -- ethcore/src/error.rs | 34 ++++++++++++++++------------- ethcore/src/ethereum/ethash.rs | 9 ++++---- ethcore/src/verification.rs | 8 +++---- rpc/src/v1/impls/eth.rs | 13 ++++++++--- sync/src/chain.rs | 12 +++++----- 9 files changed, 102 insertions(+), 56 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 28005b17e..f72c2f800 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -21,7 +21,7 @@ use common::*; use engine::*; use state::*; -use verification::PreVerifiedBlock; +use verification::PreverifiedBlock; /// A block, encoded as it is on the block chain. // TODO: rename to Block @@ -302,6 +302,18 @@ impl ClosedBlock { Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) } + /// Provide a valid seal in order to turn this into a `SealedBlock`. + /// This does check the validity of `seal` with the engine. + /// Returns the `ClosedBlock` back again if the seal is no good. + pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { + let mut s = self; + s.block.base.header.set_seal(seal); + match engine.verify_block_basic(&s.block.base.header, None).is_err() || engine.verify_block_unordered(&s.block.base.header, None).is_err() { + false => Err(s), + true => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), + } + } + /// Drop this object and return the underlieing database. pub fn drain(self) -> JournalDB { self.block.state.drop().1 } } @@ -350,7 +362,7 @@ pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: & } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified(block: &PreVerifiedBlock, engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { let view = BlockView::new(&block.bytes); enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) } diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 668c004e5..143f53647 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -28,7 +28,7 @@ use service::*; use client::BlockStatus; use util::panics::*; -known_heap_size!(0, UnVerifiedBlock, VerifyingBlock, PreVerifiedBlock); +known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock); const MIN_MEM_LIMIT: usize = 16384; const MIN_QUEUE_LIMIT: usize = 512; @@ -105,14 +105,14 @@ pub struct BlockQueue { max_mem_use: usize, } -struct UnVerifiedBlock { +struct UnverifiedBlock { header: Header, bytes: Bytes, } struct VerifyingBlock { hash: H256, - block: Option, + block: Option, } struct QueueSignal { @@ -134,8 +134,8 @@ impl QueueSignal { #[derive(Default)] struct Verification { - unverified: VecDeque, - verified: VecDeque, + unverified: VecDeque, + verified: VecDeque, verifying: VecDeque, bad: HashSet, } @@ -244,7 +244,7 @@ impl BlockQueue { } } - fn drain_verifying(verifying: &mut VecDeque, verified: &mut VecDeque, bad: &mut HashSet) { + fn drain_verifying(verifying: &mut VecDeque, verified: &mut VecDeque, bad: &mut HashSet) { while !verifying.is_empty() && verifying.front().unwrap().block.is_some() { let block = verifying.pop_front().unwrap().block.unwrap(); if bad.contains(&block.header.parent_hash) { @@ -289,31 +289,31 @@ impl BlockQueue { let header = BlockView::new(&bytes).header(); let h = header.hash(); if self.processing.read().unwrap().contains(&h) { - return Err(ImportError::AlreadyQueued); + return Err(x!(ImportError::AlreadyQueued)); } { let mut verification = self.verification.lock().unwrap(); if verification.bad.contains(&h) { - return Err(ImportError::Bad(None)); + return Err(x!(ImportError::KnownBad)); } if verification.bad.contains(&header.parent_hash) { verification.bad.insert(h.clone()); - return Err(ImportError::Bad(None)); + return Err(x!(ImportError::KnownBad)); } } match verify_block_basic(&header, &bytes, self.engine.deref().deref()) { Ok(()) => { self.processing.write().unwrap().insert(h.clone()); - self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes }); + self.verification.lock().unwrap().unverified.push_back(UnverifiedBlock { header: header, bytes: bytes }); self.more_to_verify.notify_all(); Ok(h) }, Err(err) => { warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); self.verification.lock().unwrap().bad.insert(h.clone()); - Err(From::from(err)) + Err(err) } } } @@ -352,7 +352,7 @@ impl BlockQueue { } /// Removes up to `max` verified blocks from the queue - pub fn drain(&mut self, max: usize) -> Vec { + pub fn drain(&mut self, max: usize) -> Vec { let mut verification = self.verification.lock().unwrap(); let count = min(max, verification.verified.len()); let mut result = Vec::with_capacity(count); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index f634579ad..d4fdb66c4 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -176,7 +176,7 @@ pub struct ClientReport { impl ClientReport { /// Alter internal reporting to reflect the additional `block` has been processed. - pub fn accrue_block(&mut self, block: &PreVerifiedBlock) { + pub fn accrue_block(&mut self, block: &PreverifiedBlock) { self.blocks_imported += 1; self.transactions_applied += block.transactions.len(); self.gas_processed = self.gas_processed + block.header.gas_used; @@ -257,7 +257,7 @@ impl Client { last_hashes } - fn check_and_close_block(&self, block: &PreVerifiedBlock) -> Result { + fn check_and_close_block(&self, block: &PreverifiedBlock) -> Result { let engine = self.engine.deref().deref(); let header = &block.header; @@ -433,6 +433,28 @@ impl Client { /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. pub fn sealing_block(&self) -> &Mutex> { &self.sealing_block } + + /// Submit `seal` as a valid solution for the header of `pow_hash`. + pub fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { + let mut maybe_b = self.sealing_block.lock().unwrap(); + match *maybe_b { + Some(ref b) if b.hash() == pow_hash => {} + _ => { return Err(Error::PowHashInvalid); } + } + + let b = maybe_b.take(); + match b.unwrap().try_seal(self.engine.deref().deref(), seal) { + Err(old) => { + *maybe_b = Some(old); + Err(Error::PowInvalid) + } + Ok(sealed) => { + // TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice. + try!(self.import_block(sealed.rlp_bytes())); + Ok(()) + } + } + } } // TODO: need MinerService MinerIoHandler @@ -509,12 +531,14 @@ impl BlockChainClient for Client { } fn import_block(&self, bytes: Bytes) -> ImportResult { - let header = BlockView::new(&bytes).header(); - if self.chain.read().unwrap().is_known(&header.hash()) { - return Err(ImportError::AlreadyInChain); - } - if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { - return Err(ImportError::UnknownParent); + { + let header = BlockView::new(&bytes).header_view(); + if self.chain.read().unwrap().is_known(&header.sha3()) { + return Err(x!(ImportError::AlreadyInChain)); + } + if self.block_status(BlockId::Hash(header.parent_hash())) == BlockStatus::Unknown { + return Err(x!(BlockError::UnknownParent(header.parent_hash()))); + } } self.block_queue.write().unwrap().import_block(bytes) } diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index f86c943ee..c57be3cdb 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -30,8 +30,6 @@ pub trait Engine : Sync + Send { /// The number of additional header fields required for this engine. fn seal_fields(&self) -> usize { 0 } - /// Default values of the additional fields RLP-encoded in a raw (non-list) harness. - fn seal_rlp(&self) -> Bytes { vec![] } /// Additional engine-specific information for the user/developer concerning `header`. fn extra_info(&self, _header: &Header) -> HashMap { HashMap::new() } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index f75f338bf..824d8da90 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -131,25 +131,14 @@ pub enum BlockError { #[derive(Debug)] /// Import to the block queue result pub enum ImportError { - /// Bad block detected - Bad(Option), - /// Already in the block chain + /// Already in the block chain. AlreadyInChain, - /// Already in the block queue + /// Already in the block queue. AlreadyQueued, - /// Unknown parent - UnknownParent, + /// Already marked as bad from a previous import (could mean parent is bad). + KnownBad, } -impl From for ImportError { - fn from(err: Error) -> ImportError { - ImportError::Bad(Some(err)) - } -} - -/// Result of import block operation. -pub type ImportResult = Result; - #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum Error { @@ -163,14 +152,29 @@ pub enum Error { Execution(ExecutionError), /// Error concerning transaction processing. Transaction(TransactionError), + /// Error concerning block import. + Import(ImportError), + /// PoW hash is invalid or out of date. + PowHashInvalid, + /// The value of the nonce or mishash is invalid. + PowInvalid, } +/// Result of import block operation. +pub type ImportResult = Result; + impl From for Error { fn from(err: TransactionError) -> Error { Error::Transaction(err) } } +impl From for Error { + fn from(err: ImportError) -> Error { + Error::Import(err) + } +} + impl From for Error { fn from(err: BlockError) -> Error { Error::Block(err) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 4f1ef1ce3..d26a7e2af 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -74,8 +74,6 @@ impl Engine for Ethash { fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) } // Two fields - mix fn seal_fields(&self) -> usize { 2 } - // Two empty data items in RLP. - fn seal_rlp(&self) -> Bytes { encode(&H64::new()).to_vec() } /// Additional engine-specific information for the user/developer concerning `header`. fn extra_info(&self, _header: &Header) -> HashMap { HashMap::new() } @@ -261,12 +259,15 @@ impl Ethash { } impl Header { - fn nonce(&self) -> H64 { + pub fn nonce(&self) -> H64 { decode(&self.seal()[1]) } - fn mix_hash(&self) -> H256 { + pub fn mix_hash(&self) -> H256 { decode(&self.seal()[0]) } + pub fn set_nonce_and_mix_hash(&mut self, nonce: &H64, mix_hash: &H256) { + self.seal = vec![encode(mix_hash).to_vec(), encode(nonce).to_vec()]; + } } #[cfg(test)] diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index ad5efd24a..f52e2e1e4 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -26,7 +26,7 @@ use engine::Engine; use blockchain::*; /// Preprocessed block data gathered in `verify_block_unordered` call -pub struct PreVerifiedBlock { +pub struct PreverifiedBlock { /// Populated block header pub header: Header, /// Populated block transactions @@ -55,8 +55,8 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash. /// Still operates on a individual block -/// Returns a PreVerifiedBlock structure populated with transactions -pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { +/// Returns a PreverifiedBlock structure populated with transactions +pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { try!(engine.verify_block_unordered(&header, Some(&bytes))); for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { try!(engine.verify_block_unordered(&u, None)); @@ -70,7 +70,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> transactions.push(t); } } - Ok(PreVerifiedBlock { + Ok(PreverifiedBlock { header: header, transactions: transactions, bytes: bytes, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 5791b7418..1b5c4739c 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -21,6 +21,7 @@ use jsonrpc_core::*; use util::hash::*; use util::uint::*; use util::sha3::*; +use util::rlp::encode; use ethcore::client::*; use ethcore::block::{IsBlock}; use ethcore::views::*; @@ -221,10 +222,10 @@ impl Eth for EthClient { let u = c.sealing_block().lock().unwrap(); match *u { Some(ref b) => { - let current_hash = b.hash(); + let pow_hash = b.hash(); let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); let seed_hash = get_seedhash(b.block().header().number()); - to_value(&(current_hash, seed_hash, target)) + to_value(&(pow_hash, seed_hash, target)) } _ => Err(Error::invalid_params()) } @@ -233,7 +234,13 @@ impl Eth for EthClient { } } -// fn submit_work(&self, _: Params) -> Result { rpc_unimplemented!() } + fn submit_work(&self, params: Params) -> Result { + from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { + let c = take_weak!(self.client); + let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; + to_value(&c.submit_seal(pow_hash, seal).is_ok()) + }) + } // fn submit_hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 6a7add27f..4b8065bc7 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -477,19 +477,19 @@ impl ChainSync { // TODO: Decompose block and add to self.headers and self.bodies instead if header.number == From::from(self.current_base_block() + 1) { match io.chain().import_block(block_rlp.as_raw().to_vec()) { - Err(ImportError::AlreadyInChain) => { + Err(Error::Import(ImportError::AlreadyInChain)) => { trace!(target: "sync", "New block already in chain {:?}", h); }, - Err(ImportError::AlreadyQueued) => { + Err(Error::Import(ImportError::AlreadyQueued)) => { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { self.last_imported_block = Some(header.number); trace!(target: "sync", "New block queued {:?}", h); }, - Err(ImportError::UnknownParent) => { + Err(Error::Block(BlockError::UnknownParent(p))) => { unknown = true; - trace!(target: "sync", "New block with unknown parent {:?}", h); + trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); }, Err(e) => { debug!(target: "sync", "Bad new block {:?} : {:?}", h, e); @@ -781,12 +781,12 @@ impl ChainSync { } match io.chain().import_block(block_rlp.out()) { - Err(ImportError::AlreadyInChain) => { + Err(Error::Import(ImportError::AlreadyInChain)) => { trace!(target: "sync", "Block already in chain {:?}", h); self.last_imported_block = Some(headers.0 + i as BlockNumber); self.last_imported_hash = Some(h.clone()); }, - Err(ImportError::AlreadyQueued) => { + Err(Error::Import(ImportError::AlreadyQueued)) => { trace!(target: "sync", "Block already queued {:?}", h); self.last_imported_block = Some(headers.0 + i as BlockNumber); self.last_imported_hash = Some(h.clone()); From 816e549d4c9656f3c0d5be5d0ef2afcc97931e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 1 Mar 2016 00:40:55 +0100 Subject: [PATCH 286/753] Changing implementation of is_empty to something more efficient --- util/src/table.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/table.rs b/util/src/table.rs index dd42f847a..f04a498f8 100644 --- a/util/src/table.rs +++ b/util/src/table.rs @@ -52,7 +52,7 @@ impl Table /// Check if there is any element in this Table pub fn is_empty(&self) -> bool { - self.len() == 0 + self.map.is_empty() || self.map.values().all(|v| v.is_empty()) } /// Get mutable reference for single Table row. From 2266d74c2aec90949803e8721e20136ae5e79d08 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 01:15:00 +0100 Subject: [PATCH 287/753] Fix JSONRPC I/O. --- Cargo.lock | 1 + ethcore/src/ethereum/ethash.rs | 10 ++++++++++ rpc/Cargo.toml | 1 + rpc/src/v1/impls/eth.rs | 15 +++++++++++---- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c225dbbe..b8a92fc3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -209,6 +209,7 @@ dependencies = [ "ethsync 0.9.99", "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index d26a7e2af..6dabe558f 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -249,6 +249,11 @@ impl Ethash { x!(U256::from((U512::one() << 256) / x!(difficulty))) } + /// Given the `block_number`, determine the seed hash for Ethash. + pub fn get_seedhash(number: BlockNumber) -> H256 { + Self::from_ethash(ethash::get_seedhash(number)) + } + fn to_ethash(hash: H256) -> EH256 { unsafe { mem::transmute(hash) } } @@ -259,12 +264,17 @@ impl Ethash { } impl Header { + /// Get the none field of the header. pub fn nonce(&self) -> H64 { decode(&self.seal()[1]) } + + /// Get the mix hash field of the header. pub fn mix_hash(&self) -> H256 { decode(&self.seal()[0]) } + + /// Set the nonce and mix hash fields of the header. pub fn set_nonce_and_mix_hash(&mut self, nonce: &H64, mix_hash: &H256) { self.seal = vec![encode(mix_hash).to_vec(), encode(nonce).to_vec()]; } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index c38684643..086fb19c1 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -9,6 +9,7 @@ build = "build.rs" [lib] [dependencies] +log = "0.3" serde = "0.7.0" serde_json = "0.7.0" jsonrpc-core = "1.2" diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 1b5c4739c..b26f38440 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -25,8 +25,7 @@ use util::rlp::encode; use ethcore::client::*; use ethcore::block::{IsBlock}; use ethcore::views::*; -extern crate ethash; -use self::ethash::get_seedhash; +//#[macro_use] extern crate log; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; @@ -216,6 +215,7 @@ impl Eth for EthClient { } fn work(&self, params: Params) -> Result { + println!("Work wanted: {:?}", params); match params { Params::None => { let c = take_weak!(self.client); @@ -224,7 +224,7 @@ impl Eth for EthClient { Some(ref b) => { let pow_hash = b.hash(); let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); - let seed_hash = get_seedhash(b.block().header().number()); + let seed_hash = Ethash::get_seedhash(b.block().header().number()); to_value(&(pow_hash, seed_hash, target)) } _ => Err(Error::invalid_params()) @@ -235,6 +235,7 @@ impl Eth for EthClient { } fn submit_work(&self, params: Params) -> Result { + println!("Work submission: {:?}", params); from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { let c = take_weak!(self.client); let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; @@ -242,7 +243,13 @@ impl Eth for EthClient { }) } -// fn submit_hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } + fn submit_hashrate(&self, params: Params) -> Result { + println!("Hashrate submission: {:?}", params); + from_params::<(Index, H256)>(params).and_then(|(rate, id)| { + println!("Miner {} reports a hash rate of {} H/s", id, rate.value()); + to_value(&true) + }) + } } /// Eth filter rpc implementation. From 5ccb172e73a1bf0b7b16545c0560184beef8d9d8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 01:52:22 +0100 Subject: [PATCH 288/753] Hashrate now reported correctly. --- ethcore/src/client.rs | 4 ++-- rpc/src/v1/impls/eth.rs | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index d4fdb66c4..c5aa987f6 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -417,7 +417,7 @@ impl Client { /// New chain head event. pub fn new_chain_head(&self) { let h = self.chain.read().unwrap().best_block_hash(); - info!("New best block: #{}: {}", self.chain.read().unwrap().best_block_number(), h); + debug!("New best block: #{}: {}", self.chain.read().unwrap().best_block_number(), h); let b = OpenBlock::new( self.engine.deref().deref(), self.state_db.lock().unwrap().clone(), @@ -427,7 +427,7 @@ impl Client { b"Parity".to_vec() ); let b = b.close(); - info!("Sealed: hash={}, diff={}, number={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); + debug!("Sealing: hash={}, diff={}, number={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); *self.sealing_block.lock().unwrap() = Some(b); } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index b26f38440..f96d69ce7 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,12 +15,12 @@ // along with Parity. If not, see . //! Eth rpc implementation. -use std::sync::{Arc, Weak}; use ethsync::{EthSync, SyncState}; use jsonrpc_core::*; use util::hash::*; use util::uint::*; use util::sha3::*; +use util::standard::{RwLock, HashMap, Arc, Weak}; use util::rlp::encode; use ethcore::client::*; use ethcore::block::{IsBlock}; @@ -34,7 +34,8 @@ use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncIn /// Eth rpc implementation. pub struct EthClient { client: Weak, - sync: Weak + sync: Weak, + hashrates: RwLock>, } impl EthClient { @@ -42,7 +43,8 @@ impl EthClient { pub fn new(client: &Arc, sync: &Arc) -> Self { EthClient { client: Arc::downgrade(client), - sync: Arc::downgrade(sync) + sync: Arc::downgrade(sync), + hashrates: RwLock::new(HashMap::new()), } } @@ -137,7 +139,7 @@ impl Eth for EthClient { // TODO: return real hashrate once we have mining fn hashrate(&self, params: Params) -> Result { match params { - Params::None => to_value(&U256::zero()), + Params::None => to_value(&self.hashrates.read().unwrap().iter().fold(0u64, |sum, (_, v)| sum + v)), _ => Err(Error::invalid_params()) } } @@ -215,7 +217,6 @@ impl Eth for EthClient { } fn work(&self, params: Params) -> Result { - println!("Work wanted: {:?}", params); match params { Params::None => { let c = take_weak!(self.client); @@ -235,6 +236,7 @@ impl Eth for EthClient { } fn submit_work(&self, params: Params) -> Result { + // TODO: println! should be debug! println!("Work submission: {:?}", params); from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { let c = take_weak!(self.client); @@ -244,9 +246,9 @@ impl Eth for EthClient { } fn submit_hashrate(&self, params: Params) -> Result { - println!("Hashrate submission: {:?}", params); + // TODO: Index should be U256. from_params::<(Index, H256)>(params).and_then(|(rate, id)| { - println!("Miner {} reports a hash rate of {} H/s", id, rate.value()); + self.hashrates.write().unwrap().insert(id, rate.value() as u64); to_value(&true) }) } From 1eca9acffb2f952678d7135f059139b650eec289 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 02:33:41 +0100 Subject: [PATCH 289/753] Fix is_mining. --- rpc/src/v1/impls/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index f96d69ce7..24ecbe5f1 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -131,7 +131,7 @@ impl Eth for EthClient { // TODO: return real value of mining once it's implemented. fn is_mining(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::Bool(false)), + Params::None => to_value(&!self.hashrates.read().unwrap().is_empty()), _ => Err(Error::invalid_params()) } } From c45d3560b84e1577cabb546422d7bb065ee06536 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Tue, 1 Mar 2016 10:09:22 +0800 Subject: [PATCH 290/753] fixup install script It's renamed in upstream. https://github.com/brson/multirust/commit/ae8e470ca6adc3f1c6844b6a23932902e5fd3ebc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f8b24f088..4fd2a53cc 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ First (if you don't already have it) get multirust: - Linux: ```bash -curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes +curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes ``` - OSX with Homebrew: From ab9fddf6b2e4d00e4961d98bb418679af5325e4e Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 1 Mar 2016 13:44:09 +0100 Subject: [PATCH 291/753] blockchain generator --- ethcore/src/blockchain/blockchain.rs | 41 +++--- ethcore/src/blockchain/helpers/generators.rs | 138 +++++++++++++++++++ ethcore/src/blockchain/helpers/mod.rs | 3 + ethcore/src/blockchain/mod.rs | 2 + 4 files changed, 165 insertions(+), 19 deletions(-) create mode 100644 ethcore/src/blockchain/helpers/generators.rs create mode 100644 ethcore/src/blockchain/helpers/mod.rs diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8aa0fffdc..cc95b4f3b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -447,7 +447,7 @@ impl BlockChain { let mut write_details = self.block_details.write().unwrap(); for (hash, details) in update.block_details.into_iter() { - batch.put_extras(&hash, &details); + batch.put_extras(&hash, &details); write_details.insert(hash, details); } @@ -572,7 +572,7 @@ impl BlockChain { /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); - let transaction_hashes = block.transaction_hashes(); + let transaction_hashes = block.transaction_hashes(); transaction_hashes.into_iter() .enumerate() @@ -587,20 +587,20 @@ impl BlockChain { /// This functions returns modified blocks blooms. /// - /// To accelerate blooms lookups, blomms are stored in multiple - /// layers (BLOOM_LEVELS, currently 3). + /// To accelerate blooms lookups, blomms are stored in multiple + /// layers (BLOOM_LEVELS, currently 3). /// ChainFilter is responsible for building and rebuilding these layers. /// It returns them in HashMap, where values are Blooms and /// keys are BloomIndexes. BloomIndex represents bloom location on one /// of these layers. - /// + /// /// To reduce number of queries to databse, block blooms are stored - /// in BlocksBlooms structure which contains info about several + /// in BlocksBlooms structure which contains info about several /// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms. - /// + /// /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex) /// to bloom location in database (BlocksBloomLocation). - /// + /// fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); let header = block.header_view(); @@ -766,32 +766,33 @@ mod tests { use std::str::FromStr; use rustc_serialize::hex::FromHex; use util::hash::*; + use util::sha3::Hashable; use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; use tests::helpers::*; use devtools::*; + use blockchain::helpers::generators::ChainGenerator; + use views::BlockView; #[test] - fn valid_tests_extra32() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap(); + fn basic_blockchain_insert() { + let mut canon_chain = ChainGenerator::default(); + let genesis = canon_chain.next().unwrap(); + let first = canon_chain.next().unwrap(); + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + let first_hash = BlockView::new(&first).header_view().sha3(); let temp = RandomTempPath::new(); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); - let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap(); - assert_eq!(bc.genesis_hash(), genesis_hash.clone()); assert_eq!(bc.best_block_number(), 0); assert_eq!(bc.best_block_hash(), genesis_hash.clone()); assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.block_hash(1), None); assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); - - let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); bc.insert_block(&first, vec![]); - let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap(); - assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.best_block_number(), 1); assert_eq!(bc.best_block_hash(), first_hash.clone()); @@ -961,7 +962,7 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); bc.insert_block(&b1, vec![]); - + let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); for t in transactions { @@ -981,7 +982,7 @@ mod tests { // prepare for fork (b1a, child of genesis) let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - + // fork (b2a, child of b1a, with higher total difficulty) let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); @@ -1001,7 +1002,7 @@ mod tests { let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); assert_eq!(blocks_b1, vec![]); assert_eq!(blocks_b2, vec![]); - + bc.insert_block(&b1, vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); @@ -1043,4 +1044,6 @@ mod tests { } + + } diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/helpers/generators.rs new file mode 100644 index 000000000..8416a07ad --- /dev/null +++ b/ethcore/src/blockchain/helpers/generators.rs @@ -0,0 +1,138 @@ +use util::rlp::*; +use util::hash::{H256, H2048}; +use util::uint::{U256}; +use util::bytes::Bytes; +use header::{BlockNumber, Header}; +use transaction::SignedTransaction; + +/// Chain iterator interface. +pub trait ChainIterator: Iterator { + /// Should be called to create a fork of current iterator. + /// Blocks generated by fork will have lower difficulty than current chain. + fn fork(&mut self) -> Self; + /// Should be called to create new block with given bloom. + fn next_with_bloom(&mut self, bloom: H2048) -> Option; +} + +/// Helper structure, used for encoding blocks. +#[derive(Default)] +struct Block { + header: Header, + transactions: Vec, + uncles: Vec
+} + +impl Encodable for Block { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(3); + s.append(&self.header); + s.append(&self.transactions); + s.append(&self.uncles); + } +} + +/// Blockchain generator. +pub struct ChainGenerator { + /// Next block number. + number: BlockNumber, + /// Next block parent hash. + parent_hash: H256, + /// Next block difficulty. + difficulty: U256, + /// Number of forks of current block. + number_of_forks: usize, +} + +impl ChainGenerator { + fn prepare_block(&self) -> Block { + let mut block = Block::default(); + block.header.parent_hash = self.parent_hash.clone(); + block.header.number = self.number; + block.header.difficulty = self.difficulty; + block + } +} + +impl Default for ChainGenerator { + fn default() -> Self { + ChainGenerator { + number: 0, + parent_hash: H256::default(), + difficulty: U256::from(1000), + number_of_forks: 0 + } + } +} + +impl Iterator for ChainGenerator { + type Item = Bytes; + + fn next(&mut self) -> Option { + let block = self.prepare_block(); + self.number += 1; + self.parent_hash = block.header.hash(); + self.number_of_forks = 0; + Some(encode(&block).to_vec()) + } +} + +impl ChainIterator for ChainGenerator { + fn fork(&mut self) -> Self { + self.number_of_forks += 1; + ChainGenerator { + number: self.number, + parent_hash: self.parent_hash.clone(), + difficulty: self.difficulty - U256::from(self.number_of_forks), + number_of_forks: 0 + } + } + + fn next_with_bloom(&mut self, bloom: H2048) -> Option { + let mut block = self.prepare_block(); + block.header.log_bloom = bloom; + self.number += 1; + self.parent_hash = block.header.hash(); + self.number_of_forks = 0; + Some(encode(&block).to_vec()) + } +} + +#[cfg(test)] +mod tests { + use util::hash::H256; + use util::sha3::Hashable; + use views::BlockView; + use super::{ChainIterator, ChainGenerator}; + + #[test] + fn canon_chain_generator() { + let mut canon_chain = ChainGenerator::default(); + + let genesis_rlp = canon_chain.next().unwrap(); + let genesis = BlockView::new(&genesis_rlp); + + assert_eq!(genesis.header_view().parent_hash(), H256::default()); + assert_eq!(genesis.header_view().number(), 0); + + let b1_rlp = canon_chain.next().unwrap(); + let b1 = BlockView::new(&b1_rlp); + + assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3()); + assert_eq!(b1.header_view().number(), 1); + + let mut fork_chain = canon_chain.fork(); + + let b2_rlp_fork = fork_chain.next().unwrap(); + let b2_fork = BlockView::new(&b2_rlp_fork); + + assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3()); + assert_eq!(b2_fork.header_view().number(), 2); + + let b2_rlp = canon_chain.next().unwrap(); + let b2 = BlockView::new(&b2_rlp); + + assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3()); + assert_eq!(b2.header_view().number(), 2); + assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty()); + } +} diff --git a/ethcore/src/blockchain/helpers/mod.rs b/ethcore/src/blockchain/helpers/mod.rs new file mode 100644 index 000000000..0240bd00f --- /dev/null +++ b/ethcore/src/blockchain/helpers/mod.rs @@ -0,0 +1,3 @@ +pub mod generators; + +//pub use self::blockchain_builder::BlockChainBuilder; diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index c1046d960..60a1aeb33 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -23,6 +23,8 @@ mod bloom_indexer; mod cache; mod tree_route; mod update; +#[cfg(test)] +mod helpers; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize; From 063020f5075f245b0c70c1a5c1918229efe25fe4 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 1 Mar 2016 13:46:33 +0100 Subject: [PATCH 292/753] added license headers --- ethcore/src/blockchain/helpers/generators.rs | 16 ++++++++++++++++ ethcore/src/blockchain/helpers/mod.rs | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/helpers/generators.rs index 8416a07ad..75e7655eb 100644 --- a/ethcore/src/blockchain/helpers/generators.rs +++ b/ethcore/src/blockchain/helpers/generators.rs @@ -1,3 +1,19 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + use util::rlp::*; use util::hash::{H256, H2048}; use util::uint::{U256}; diff --git a/ethcore/src/blockchain/helpers/mod.rs b/ethcore/src/blockchain/helpers/mod.rs index 0240bd00f..233f8f1f8 100644 --- a/ethcore/src/blockchain/helpers/mod.rs +++ b/ethcore/src/blockchain/helpers/mod.rs @@ -1,3 +1,17 @@ -pub mod generators; +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. -//pub use self::blockchain_builder::BlockChainBuilder; +// 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 . + +pub mod generators; From 47688e49cd19f68660ddff28c51f437019b3cb7d Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 1 Mar 2016 13:54:14 +0100 Subject: [PATCH 293/753] removed redundant whitespaces --- ethcore/src/blockchain/blockchain.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index cc95b4f3b..0aba36a8e 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1042,8 +1042,4 @@ mod tests { assert_eq!(blocks_b2, vec![2]); assert_eq!(blocks_ba, vec![3]); } - - - - } From 3e2366b38b7d467ec4badafcee4d45bfc370a644 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 1 Mar 2016 16:22:06 +0100 Subject: [PATCH 294/753] improved chain generator --- ethcore/src/blockchain/blockchain.rs | 32 ++--- ethcore/src/blockchain/helpers/generators.rs | 119 +++++++++++++------ 2 files changed, 102 insertions(+), 49 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 0aba36a8e..53dcfb62c 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -770,14 +770,14 @@ mod tests { use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; use tests::helpers::*; use devtools::*; - use blockchain::helpers::generators::ChainGenerator; + use blockchain::helpers::generators::{ChainGenerator, ChainIterator}; use views::BlockView; #[test] fn basic_blockchain_insert() { let mut canon_chain = ChainGenerator::default(); - let genesis = canon_chain.next().unwrap(); - let first = canon_chain.next().unwrap(); + let genesis = canon_chain.next().unwrap().rlp(); + let first = canon_chain.next().unwrap().rlp(); let genesis_hash = BlockView::new(&genesis).header_view().sha3(); let first_hash = BlockView::new(&first).header_view().sha3(); @@ -805,20 +805,24 @@ mod tests { #[test] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); - let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); - let b2 = "f902ccf901f9a0437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - let b3a = "f90261f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a09dc4b1357c0b7b8108f8a098f4f9a1a274957bc9ebc22a9ae67ae81739e5b19ca007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882524d84562791eb80a074861666bd346c025889745c793b91ab9cd1e2ca19b5cf3c50d04d135b0a4d2b8809fe9587ea4cdc04f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba06fd84874d36d5de9e8e48978c03619b53a96b7ae0a4cd1ac118f103098b44801a00572596974dd7df4f9f69bd7456585618c568d8434ef6453391b89281ce12ae1c0".from_hex().unwrap(); - let b3b = "f90265f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ab87dc338bfd6f662b1cd90bc0c9e40a1b2146a095312393c9e13ce3a5008b09a0e609b7a7d4b8a2403ec1268627ecd98783627246e8f1b26addb3ff504f76a054a0592fabf92476512952db3a69a2481a42912e668a1ee28c4c322e703bb665f8beb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882a1f084562791ee80a0fe7098fa7e4ac5d637eea81fb23f8f78346826dbab430068dd9a249d0afa99818853e1a6b201ae3545f866f86402018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d0284c04062261ca06edc9ce8e7da4cc34067beb325dcad59e5655a164a5100a50bc3eb681b12c716a0abf9053d5de65b1be81fe50d327b84de685efbeecea34e7b747180a6c6023e44c0".from_hex().unwrap(); + let mut canon_chain = ChainGenerator::default(); + let genesis = canon_chain.next().unwrap().rlp(); + let blocks = canon_chain.clone().take(3).map(|block| block.rlp()).collect::>(); + let fork = canon_chain.skip(2).fork(1).take(1).next().unwrap().rlp(); - let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap(); - let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap(); - let b2_hash = H256::from_str("36fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781a").unwrap(); - let b3a_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap(); - let b3b_hash = H256::from_str("bf72270ae0d95c9ea39a6adab994793fddb8c10fba7391e26279474124605d54").unwrap(); + let b1 = blocks[0].clone(); + let b2 = blocks[1].clone(); + let b3a = blocks[2].clone(); + let b3b = fork; + + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + let b1_hash= BlockView::new(&b1).header_view().sha3(); + let b2_hash= BlockView::new(&b2).header_view().sha3(); + let b3a_hash= BlockView::new(&b3a).header_view().sha3(); + let b3b_hash= BlockView::new(&b3b).header_view().sha3(); // b3a is a part of canon chain, whereas b3b is part of sidechain - let best_block_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap(); + let best_block_hash = b3a_hash.clone(); let temp = RandomTempPath::new(); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/helpers/generators.rs index 75e7655eb..a20b0cf79 100644 --- a/ethcore/src/blockchain/helpers/generators.rs +++ b/ethcore/src/blockchain/helpers/generators.rs @@ -21,23 +21,81 @@ use util::bytes::Bytes; use header::{BlockNumber, Header}; use transaction::SignedTransaction; +pub trait Forkable { + fn fork(self, fork_number: usize) -> Self where Self: Sized; +} + +pub struct Fork { + iter: I, + fork_number: usize, +} + +impl Iterator for Fork where I: Iterator, ::Item: Forkable { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| item.fork(self.fork_number)) + } +} + +pub trait WithBloom { + fn with_bloom(self, bloom: H2048) -> Self where Self: Sized; +} + +pub struct Bloom { + iter: I, + bloom: H2048, +} + +impl Iterator for Bloom where I: Iterator, ::Item: WithBloom { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| item.with_bloom(self.bloom.clone())) + } +} + /// Chain iterator interface. pub trait ChainIterator: Iterator { /// Should be called to create a fork of current iterator. /// Blocks generated by fork will have lower difficulty than current chain. - fn fork(&mut self) -> Self; - /// Should be called to create new block with given bloom. - fn next_with_bloom(&mut self, bloom: H2048) -> Option; + fn fork(&mut self, fork_number: usize) -> Fork where Self: Sized; + /// Should be called to make every consecutive block have given bloom. + fn with_bloom(&mut self, bloom: H2048) -> Bloom where Self: Sized; +} + +impl ChainIterator for I where I: Iterator + Sized + Clone { + fn fork(&mut self, fork_number: usize) -> Fork { + Fork { + iter: self.clone(), + fork_number: fork_number + } + } + + fn with_bloom(&mut self, bloom: H2048) -> Bloom { + Bloom { + iter: self.clone(), + bloom: bloom + } + } } /// Helper structure, used for encoding blocks. #[derive(Default)] -struct Block { +pub struct Block { header: Header, transactions: Vec, uncles: Vec
} +impl Block { + pub fn rlp(&self) -> Bytes { + encode(self).to_vec() + } +} + impl Encodable for Block { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(3); @@ -47,7 +105,22 @@ impl Encodable for Block { } } +impl Forkable for Block { + fn fork(mut self, fork_number: usize) -> Self where Self: Sized { + self.header.difficulty = self.header.difficulty - U256::from(fork_number); + self + } +} + +impl WithBloom for Block { + fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized { + self.header.log_bloom = bloom; + self + } +} + /// Blockchain generator. +#[derive(Clone)] pub struct ChainGenerator { /// Next block number. number: BlockNumber, @@ -55,8 +128,6 @@ pub struct ChainGenerator { parent_hash: H256, /// Next block difficulty. difficulty: U256, - /// Number of forks of current block. - number_of_forks: usize, } impl ChainGenerator { @@ -75,43 +146,21 @@ impl Default for ChainGenerator { number: 0, parent_hash: H256::default(), difficulty: U256::from(1000), - number_of_forks: 0 } } } impl Iterator for ChainGenerator { - type Item = Bytes; + type Item = Block; fn next(&mut self) -> Option { let block = self.prepare_block(); self.number += 1; self.parent_hash = block.header.hash(); - self.number_of_forks = 0; - Some(encode(&block).to_vec()) + Some(block) } } -impl ChainIterator for ChainGenerator { - fn fork(&mut self) -> Self { - self.number_of_forks += 1; - ChainGenerator { - number: self.number, - parent_hash: self.parent_hash.clone(), - difficulty: self.difficulty - U256::from(self.number_of_forks), - number_of_forks: 0 - } - } - - fn next_with_bloom(&mut self, bloom: H2048) -> Option { - let mut block = self.prepare_block(); - block.header.log_bloom = bloom; - self.number += 1; - self.parent_hash = block.header.hash(); - self.number_of_forks = 0; - Some(encode(&block).to_vec()) - } -} #[cfg(test)] mod tests { @@ -124,27 +173,27 @@ mod tests { fn canon_chain_generator() { let mut canon_chain = ChainGenerator::default(); - let genesis_rlp = canon_chain.next().unwrap(); + let genesis_rlp = canon_chain.next().unwrap().rlp(); let genesis = BlockView::new(&genesis_rlp); assert_eq!(genesis.header_view().parent_hash(), H256::default()); assert_eq!(genesis.header_view().number(), 0); - let b1_rlp = canon_chain.next().unwrap(); + let b1_rlp = canon_chain.next().unwrap().rlp(); let b1 = BlockView::new(&b1_rlp); assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3()); assert_eq!(b1.header_view().number(), 1); - let mut fork_chain = canon_chain.fork(); + let mut fork_chain = canon_chain.fork(1); - let b2_rlp_fork = fork_chain.next().unwrap(); + let b2_rlp_fork = fork_chain.next().unwrap().rlp(); let b2_fork = BlockView::new(&b2_rlp_fork); assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3()); assert_eq!(b2_fork.header_view().number(), 2); - let b2_rlp = canon_chain.next().unwrap(); + let b2_rlp = canon_chain.next().unwrap().rlp(); let b2 = BlockView::new(&b2_rlp); assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3()); From 48df869202571360b4554544bf4400f19a0236d3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 16:58:14 +0100 Subject: [PATCH 295/753] --author and --extra-data options. Fixed null parent-hash. --- ethcore/src/block.rs | 12 +++++++--- ethcore/src/client.rs | 50 +++++++++++++++++++++++++++++++++-------- ethcore/src/header.rs | 10 ++++++--- parity/main.rs | 20 +++++++++++++++++ rpc/src/v1/impls/eth.rs | 6 ++--- util/src/misc.rs | 15 +++++++++++++ 6 files changed, 95 insertions(+), 18 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index f72c2f800..16d3e2216 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -182,6 +182,7 @@ impl<'x> OpenBlock<'x> { r.block.base.header.set_author(author); r.block.base.header.set_extra_data(extra_data); r.block.base.header.set_timestamp_now(parent.timestamp()); + r.block.base.header.set_parent_hash(parent.hash()); engine.populate_from_parent(&mut r.block.base.header, parent); engine.on_new_block(&mut r.block); @@ -308,10 +309,15 @@ impl ClosedBlock { pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { let mut s = self; s.block.base.header.set_seal(seal); - match engine.verify_block_basic(&s.block.base.header, None).is_err() || engine.verify_block_unordered(&s.block.base.header, None).is_err() { - false => Err(s), - true => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), + if let Err(e) = engine.verify_block_basic(&s.block.base.header, None) { + debug!("Failed to try_seal: {:?}", e); + return Err(s); } + if let Err(e) = engine.verify_block_unordered(&s.block.base.header, None) { + debug!("Failed to try_seal: {:?}", e); + return Err(s); + } + Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) } /// Drop this object and return the underlieing database. diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c5aa987f6..de875348a 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -196,6 +196,8 @@ pub struct Client { // for sealing... sealing_block: Mutex>, + author: RwLock
, + extra_data: RwLock, } const HISTORY: u64 = 1000; @@ -233,6 +235,8 @@ impl Client { import_lock: Mutex::new(()), panic_handler: panic_handler, sealing_block: Mutex::new(None), + author: RwLock::new(Address::new()), + extra_data: RwLock::new(Vec::new()), })) } @@ -364,7 +368,7 @@ impl Client { } if self.chain_info().best_block_hash != original_best { - self.new_chain_head(); + self.prepare_sealing(); } imported @@ -414,27 +418,55 @@ impl Client { } } - /// New chain head event. - pub fn new_chain_head(&self) { + /// Set the author that we will seal blocks as. + pub fn author(&self) -> Address { + self.author.read().unwrap().clone() + } + + /// Set the author that we will seal blocks as. + pub fn set_author(&self, author: Address) { + *self.author.write().unwrap() = author; + } + + /// Set the extra_data that we will seal blocks wuth. + pub fn extra_data(&self) -> Bytes { + self.extra_data.read().unwrap().clone() + } + + /// Set the extra_data that we will seal blocks with. + pub fn set_extra_data(&self, extra_data: Bytes) { + *self.extra_data.write().unwrap() = extra_data; + } + + /// New chain head event. Restart mining operation. + pub fn prepare_sealing(&self) { let h = self.chain.read().unwrap().best_block_hash(); - debug!("New best block: #{}: {}", self.chain.read().unwrap().best_block_number(), h); let b = OpenBlock::new( self.engine.deref().deref(), self.state_db.lock().unwrap().clone(), match self.chain.read().unwrap().block_header(&h) { Some(ref x) => x, None => {return;} }, - self.build_last_hashes(h.clone()), - x!("0037a6b811ffeb6e072da21179d11b1406371c63"), - b"Parity".to_vec() + self.build_last_hashes(h), + self.author(), + self.extra_data() ); + // TODO: push uncles. + // TODO: push transactions. let b = b.close(); - debug!("Sealing: hash={}, diff={}, number={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); + trace!("Sealing: number={}, hash={}, diff={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); + debug!("Header: {:?}", b.block().header()); *self.sealing_block.lock().unwrap() = Some(b); } /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - pub fn sealing_block(&self) -> &Mutex> { &self.sealing_block } + pub fn sealing_block(&self) -> &Mutex> { + if self.sealing_block.lock().unwrap().is_none() { + self.prepare_sealing(); + } + &self.sealing_block + } /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. pub fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { let mut maybe_b = self.sealing_block.lock().unwrap(); match *maybe_b { diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 3db0be5ff..cc02d84db 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -102,10 +102,12 @@ impl Header { Self::default() } - /// Get the number field of the header. - pub fn number(&self) -> BlockNumber { self.number } + /// Get the parent_hash field of the header. + pub fn parent_hash(&self) -> &H256 { &self.parent_hash } /// Get the timestamp field of the header. pub fn timestamp(&self) -> u64 { self.timestamp } + /// Get the number field of the header. + pub fn number(&self) -> BlockNumber { self.number } /// Get the author field of the header. pub fn author(&self) -> &Address { &self.author } @@ -127,11 +129,13 @@ impl Header { // TODO: seal_at, set_seal_at &c. /// Set the number field of the header. - pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } + pub fn set_parent_hash(&mut self, a: H256) { self.parent_hash = a; self.note_dirty(); } /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } /// Set the timestamp field of the header to the current time. pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = max(now_utc().to_timespec().sec as u64, but_later_than + 1); self.note_dirty(); } + /// Set the number field of the header. + pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } /// Set the author field of the header. pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } } diff --git a/parity/main.rs b/parity/main.rs index 7241a2ac4..b991f36cd 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -85,6 +85,10 @@ Options: --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. + --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards + from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. + --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. + -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. @@ -114,6 +118,8 @@ struct Args { flag_jsonrpc_cors: String, flag_logging: Option, flag_version: bool, + flag_author: String, + flag_extra_data: Option, } fn setup_log(init: &Option) { @@ -196,6 +202,18 @@ impl Configuration { self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } + fn author(&self) -> Address { + Address::from_str(&self.args.flag_author).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) + } + + fn extra_data(&self) -> Bytes { + match self.args.flag_extra_data { + Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(), + None => version_data(), + Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); } + } + } + fn _keys_path(&self) -> String { self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } @@ -296,6 +314,8 @@ impl Configuration { client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let client = service.client().clone(); + client.set_author(self.author()); + client.set_extra_data(self.extra_data()); // Sync let sync = EthSync::register(service.network(), sync_config, client); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 24ecbe5f1..a7583ddf7 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -236,12 +236,12 @@ impl Eth for EthClient { } fn submit_work(&self, params: Params) -> Result { - // TODO: println! should be debug! - println!("Work submission: {:?}", params); from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { +// trace!("Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash); let c = take_weak!(self.client); let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; - to_value(&c.submit_seal(pow_hash, seal).is_ok()) + let r = c.submit_seal(pow_hash, seal); + to_value(&r.is_ok()) }) } diff --git a/util/src/misc.rs b/util/src/misc.rs index 35e1f3a75..d9f52fd71 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -18,6 +18,7 @@ use std::fs::File; use common::*; +use rlp::{Stream, RlpStream}; use target_info::Target; use rustc_version; @@ -70,4 +71,18 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { format!("Parity//v{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) +} + +/// Get the standard version data for this software. +pub fn version_data() -> Bytes { + let mut s = RlpStream::new_list(4); + let v = + (u32::from_str(env!("CARGO_PKG_VERSION_MAJOR")).unwrap() << 16) + + (u32::from_str(env!("CARGO_PKG_VERSION_MINOR")).unwrap() << 8) + + u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(); + s.append(&v); + s.append(&"Parity"); + s.append(&format!("rustc{}", rustc_version::version())); + s.append(&Target::os()); + s.out() } \ No newline at end of file From a5c65b2a3d1aa9a13d680a7efb122be28e47f9b0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 16:59:01 +0100 Subject: [PATCH 296/753] Reduce spam. --- ethcore/src/client.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index de875348a..e5d9f8fcf 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -453,7 +453,6 @@ impl Client { // TODO: push transactions. let b = b.close(); trace!("Sealing: number={}, hash={}, diff={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); - debug!("Header: {:?}", b.block().header()); *self.sealing_block.lock().unwrap() = Some(b); } From afc06050807867ee27a6830aaf15eee29042c60d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 17:23:44 +0100 Subject: [PATCH 297/753] Refactor engine to make it clear that we're actually checking the seal. --- ethcore/src/block.rs | 11 +++-------- ethcore/src/engine.rs | 7 +++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 16d3e2216..eb9d66124 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -309,15 +309,10 @@ impl ClosedBlock { pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { let mut s = self; s.block.base.header.set_seal(seal); - if let Err(e) = engine.verify_block_basic(&s.block.base.header, None) { - debug!("Failed to try_seal: {:?}", e); - return Err(s); + match engine.verify_block_seal(&s.block.base.header) { + Err(_) => Err(s), + _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), } - if let Err(e) = engine.verify_block_unordered(&s.block.base.header, None) { - debug!("Failed to try_seal: {:?}", e); - return Err(s); - } - Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) } /// Drop this object and return the underlieing database. diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index c57be3cdb..a05c78ff5 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -74,6 +74,13 @@ pub trait Engine : Sync + Send { /// Verify a particular transaction is valid. fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } + /// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods + /// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer + /// methods are needed for an Engine, this may be overridden. + fn verify_block_seal(&self, header: &Header) -> Result<(), Error> { + self.verify_block_basic(header, None).and_then(|_| self.verify_block_unordered(header, None)) + } + /// Don't forget to call Super::populateFromParent when subclassing & overriding. // TODO: consider including State in the params. fn populate_from_parent(&self, _header: &mut Header, _parent: &Header) {} From 61420d3c9c64d87ab2c83d972c7d2d812b1d9b72 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 18:17:59 +0100 Subject: [PATCH 298/753] Fix for morden consensus. --- ethcore/src/account.rs | 14 +++++++------- ethcore/src/state.rs | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index c36c35232..6901996bc 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -92,10 +92,10 @@ impl Account { /// Create a new contract account. /// NOTE: make sure you use `init_code` on this before `commit`ing. - pub fn new_contract(balance: U256) -> Account { + pub fn new_contract(balance: U256, nonce: U256) -> Account { Account { balance: balance, - nonce: U256::from(0u8), + nonce: nonce, storage_root: SHA3_NULL_RLP, storage_overlay: RefCell::new(HashMap::new()), code_hash: None, @@ -261,7 +261,7 @@ mod tests { let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); let rlp = { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); a.commit_storage(&mut db); a.init_code(vec![]); @@ -281,7 +281,7 @@ mod tests { let mut db = AccountDBMut::new(&mut db, &Address::new()); let rlp = { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); a.init_code(vec![0x55, 0x44, 0xffu8]); a.commit_code(&mut db); a.rlp() @@ -296,7 +296,7 @@ mod tests { #[test] fn commit_storage() { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.set_storage(x!(0), x!(0x1234)); @@ -307,7 +307,7 @@ mod tests { #[test] fn commit_remove_commit_storage() { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.set_storage(x!(0), x!(0x1234)); @@ -321,7 +321,7 @@ mod tests { #[test] fn commit_code() { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.init_code(vec![0x55, 0x44, 0xffu8]); diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 8bbf317c1..e35f651ee 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -138,7 +138,7 @@ impl State { /// Create a new contract at address `contract`. If there is already an account at the address /// it will have its code reset, ready for `init_code()`. pub fn new_contract(&mut self, contract: &Address, balance: U256) { - self.insert_cache(&contract, Some(Account::new_contract(balance))); + self.insert_cache(&contract, Some(Account::new_contract(balance, self.account_start_nonce))); } /// Remove an existing account. @@ -204,7 +204,7 @@ impl State { /// Initialise the code of account `a` so that it is `value` for `key`. /// NOTE: Account should have been created with `new_contract`. pub fn init_code(&mut self, a: &Address, code: Bytes) { - self.require_or_from(a, true, || Account::new_contract(U256::from(0u8)), |_|{}).init_code(code); + self.require_or_from(a, true, || Account::new_contract(x!(0), self.account_start_nonce), |_|{}).init_code(code); } /// Execute a given transaction. @@ -349,7 +349,7 @@ fn code_from_database() { let temp = RandomTempPath::new(); let (root, db) = { let mut state = get_temp_state_in(temp.as_path()); - state.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32)), |_|{}); + state.require_or_from(&a, false, ||Account::new_contract(x!(42), x!(0)), |_|{}); state.init_code(&a, vec![1, 2, 3]); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); state.commit(); From 140711dd8ac6dbd55d3210bc6609711fae73f5a1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 19:59:12 +0100 Subject: [PATCH 299/753] Fixups from review. Reduce size of default extra-data. Introduce find_uncle_headers. --- ethcore/src/block.rs | 2 +- ethcore/src/block_queue.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 6 ++++++ ethcore/src/client.rs | 13 ++++++++----- util/src/misc.rs | 4 ++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index eb9d66124..582b8669a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -404,7 +404,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(&mut db); - let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(&engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 143f53647..490a17995 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -455,7 +455,7 @@ mod tests { match duplicate_import { Err(e) => { match e { - ImportError::AlreadyQueued => {}, + Error::Import(ImportError::AlreadyQueued) => {}, _ => { panic!("must return AlreadyQueued error"); } } } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 0aba36a8e..88a6504ac 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -473,6 +473,12 @@ impl BlockChain { self.extras_db.write(batch).unwrap(); } + /// Given a block's `parent`, find every block header which represents a valid uncle. + pub fn find_uncle_headers(&self, _parent: &H256) -> Vec
{ + // TODO + Vec::new() + } + /// Get inserted block info which is critical to preapre extras updates. fn block_info(&self, block_bytes: &[u8]) -> BlockInfo { let block = BlockView::new(block_bytes); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index e5d9f8fcf..4b109c8a3 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -418,7 +418,7 @@ impl Client { } } - /// Set the author that we will seal blocks as. + /// Get the author that we will seal blocks as. pub fn author(&self) -> Address { self.author.read().unwrap().clone() } @@ -428,7 +428,7 @@ impl Client { *self.author.write().unwrap() = author; } - /// Set the extra_data that we will seal blocks wuth. + /// Get the extra_data that we will seal blocks wuth. pub fn extra_data(&self) -> Bytes { self.extra_data.read().unwrap().clone() } @@ -441,16 +441,19 @@ impl Client { /// New chain head event. Restart mining operation. pub fn prepare_sealing(&self) { let h = self.chain.read().unwrap().best_block_hash(); - let b = OpenBlock::new( + let mut b = OpenBlock::new( self.engine.deref().deref(), self.state_db.lock().unwrap().clone(), match self.chain.read().unwrap().block_header(&h) { Some(ref x) => x, None => {return;} }, - self.build_last_hashes(h), + self.build_last_hashes(h.clone()), self.author(), self.extra_data() ); - // TODO: push uncles. + + self.chain.read().unwrap().find_uncle_headers(&h).into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); + // TODO: push transactions. + let b = b.close(); trace!("Sealing: number={}, hash={}, diff={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); *self.sealing_block.lock().unwrap() = Some(b); diff --git a/util/src/misc.rs b/util/src/misc.rs index d9f52fd71..6cd506d02 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -82,7 +82,7 @@ pub fn version_data() -> Bytes { u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(); s.append(&v); s.append(&"Parity"); - s.append(&format!("rustc{}", rustc_version::version())); - s.append(&Target::os()); + s.append(&format!("{}", rustc_version::version())); + s.append(&&Target::os()[0..2]); s.out() } \ No newline at end of file From 628a53cceca9ad2b66d8c7510331ad23cc50134c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 20:02:59 +0100 Subject: [PATCH 300/753] Update tests. Fix our tests. --- ethcore/res/ethereum/tests | 2 +- ethcore/src/block.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index f32954b3d..99afe8f5a 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit f32954b3ddb5af2dc3dc9ec6d9a28bee848fdf70 +Subproject commit 99afe8f5aad7bca5d0f1b1685390a4dea32d73c3 diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 582b8669a..0ca6e88be 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -404,7 +404,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(&mut db); - let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(&engine, vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); From a21fda23a6e1c954f284bfff6cf7ac2797dbec4b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 1 Mar 2016 20:14:28 +0100 Subject: [PATCH 301/753] Enable transition test. --- ethcore/src/json_tests/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index b5f28444a..f6b5751a7 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -115,7 +115,7 @@ declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} -//declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} +declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} From aab274d3ef4478120167e1076a0324580cffd516 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Thu, 18 Feb 2016 23:01:35 +0100 Subject: [PATCH 302/753] Changing RefCell to Cell in transaction. Implementing Copy on Uints. --- ethcore/src/transaction.rs | 52 ++++++++++++++++++++------------------ util/src/hash.rs | 2 ++ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index fc9886a4d..a51824494 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -100,10 +100,10 @@ impl FromJson for SignedTransaction { v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, - hash: RefCell::new(None), + hash: Cell::new(None), sender: match json.find("sender") { - Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), - _ => RefCell::new(None), + Some(&Json::String(ref sender)) => Cell::new(Some(address_from_hex(clean(sender)))), + _ => Cell::new(None), } } } @@ -127,8 +127,8 @@ impl Transaction { r: r, s: s, v: v + 27, - hash: RefCell::new(None), - sender: RefCell::new(None) + hash: Cell::new(None), + sender: Cell::new(None), } } @@ -140,8 +140,8 @@ impl Transaction { r: U256::zero(), s: U256::zero(), v: 0, - hash: RefCell::new(None), - sender: RefCell::new(None) + hash: Cell::new(None), + sender: Cell::new(None), } } @@ -171,9 +171,9 @@ pub struct SignedTransaction { /// The S field of the signature; helps describe the point on the curve. s: U256, /// Cached hash. - hash: RefCell>, + hash: Cell>, /// Cached sender. - sender: RefCell> + sender: Cell>, } impl PartialEq for SignedTransaction { @@ -208,8 +208,8 @@ impl Decodable for SignedTransaction { v: try!(d.val_at(6)), r: try!(d.val_at(7)), s: try!(d.val_at(8)), - hash: RefCell::new(None), - sender: RefCell::new(None), + hash: Cell::new(None), + sender: Cell::new(None), }) } } @@ -238,13 +238,14 @@ impl SignedTransaction { /// Get the hash of this header (sha3 of the RLP). pub fn hash(&self) -> H256 { - let mut hash = self.hash.borrow_mut(); - match &mut *hash { - &mut Some(ref h) => h.clone(), - hash @ &mut None => { - *hash = Some(self.rlp_sha3()); - hash.as_ref().unwrap().clone() - } + let hash = self.hash.get(); + match hash { + Some(h) => h, + None => { + let h = self.rlp_sha3(); + self.hash.set(Some(h)); + h + } } } @@ -265,13 +266,14 @@ impl SignedTransaction { /// Returns transaction sender. pub fn sender(&self) -> Result { - let mut sender = self.sender.borrow_mut(); - match &mut *sender { - &mut Some(ref h) => Ok(h.clone()), - sender @ &mut None => { - *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3())); - Ok(sender.as_ref().unwrap().clone()) - } + let sender = self.sender.get(); + match sender { + Some(s) => Ok(s), + None => { + let s = Address::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3()); + self.sender.set(Some(s)); + Ok(s) + } } } diff --git a/util/src/hash.rs b/util/src/hash.rs index 88c57371e..3f708631a 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -304,6 +304,8 @@ macro_rules! impl_hash { } } + impl Copy for $from {} + #[cfg_attr(feature="dev", allow(expl_impl_clone_on_copy))] impl Clone for $from { fn clone(&self) -> $from { unsafe { From 8c9c701de551d8c9d9af71991fd8ca10064f36ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 1 Mar 2016 21:31:58 +0100 Subject: [PATCH 303/753] Fixing spelling in propagade->propagate --- sync/src/chain.rs | 34 +++++++++++++++++----------------- sync/src/tests/chain.rs | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 6a7add27f..85380f3cd 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -249,14 +249,14 @@ impl ChainSync { blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), - mem_used: + mem_used: // TODO: https://github.com/servo/heapsize/pull/50 - // self.downloading_hashes.heap_size_of_children() - //+ self.downloading_bodies.heap_size_of_children() - //+ self.downloading_hashes.heap_size_of_children() - self.headers.heap_size_of_children() - + self.bodies.heap_size_of_children() - + self.peers.heap_size_of_children() + // self.downloading_hashes.heap_size_of_children() + //+ self.downloading_bodies.heap_size_of_children() + //+ self.downloading_hashes.heap_size_of_children() + self.headers.heap_size_of_children() + + self.bodies.heap_size_of_children() + + self.peers.heap_size_of_children() + self.header_ids.heap_size_of_children(), } } @@ -1171,8 +1171,8 @@ impl ChainSync { .collect::>() } - /// propagades latest block to lagging peers - fn propagade_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { + /// propagates latest block to lagging peers + fn propagate_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { let updated_peers = { let lagging_peers = self.get_lagging_peers(io); @@ -1198,8 +1198,8 @@ impl ChainSync { sent } - /// propagades new known hashes to all peers - fn propagade_new_hashes(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { + /// propagates new known hashes to all peers + fn propagate_new_hashes(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { let updated_peers = self.get_lagging_peers(io); let mut sent = 0; let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(local_best.clone())).unwrap()).parent_hash(); @@ -1234,8 +1234,8 @@ impl ChainSync { pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) { let chain = io.chain().chain_info(); if (((chain.best_block_number as i64) - (self.last_send_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let blocks = self.propagade_blocks(&chain.best_block_hash, chain.best_block_number, io); - let hashes = self.propagade_new_hashes(&chain.best_block_hash, chain.best_block_number, io); + let blocks = self.propagate_blocks(&chain.best_block_hash, chain.best_block_number, io); + let hashes = self.propagate_new_hashes(&chain.best_block_hash, chain.best_block_number, io); if blocks != 0 || hashes != 0 { trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); } @@ -1419,7 +1419,7 @@ mod tests { let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - let peer_count = sync.propagade_new_hashes(&best_hash, best_number, &mut io); + let peer_count = sync.propagate_new_hashes(&best_hash, best_number, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1439,7 +1439,7 @@ mod tests { let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - let peer_count = sync.propagade_blocks(&best_hash, best_number, &mut io); + let peer_count = sync.propagate_blocks(&best_hash, best_number, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1545,7 +1545,7 @@ mod tests { let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagade_new_hashes(&best_hash, best_number, &mut io); + sync.propagate_new_hashes(&best_hash, best_number, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(&data)); @@ -1564,7 +1564,7 @@ mod tests { let best_number = client.chain_info().best_block_number; let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagade_blocks(&best_hash, best_number, &mut io); + sync.propagate_blocks(&best_hash, best_number, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 1dd9a1e78..b01c894a0 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -121,7 +121,7 @@ fn status_packet() { } #[test] -fn propagade_hashes() { +fn propagate_hashes() { let mut net = TestNet::new(6); net.peer_mut(1).chain.add_blocks(10, false); net.sync(); @@ -147,7 +147,7 @@ fn propagade_hashes() { } #[test] -fn propagade_blocks() { +fn propagate_blocks() { let mut net = TestNet::new(2); net.peer_mut(1).chain.add_blocks(10, false); net.sync(); From 725e894f9bd26397364943df9d259211bc532844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 1 Mar 2016 21:48:58 +0100 Subject: [PATCH 304/753] TransactionsQueue implementation --- Cargo.lock | 1 + sync/Cargo.toml | 1 + sync/src/lib.rs | 2 + sync/src/transaction_queue.rs | 622 ++++++++++++++++++++++++++++++++++ 4 files changed, 626 insertions(+) create mode 100644 sync/src/transaction_queue.rs diff --git a/Cargo.lock b/Cargo.lock index bca236813..e558606eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,6 +259,7 @@ dependencies = [ "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 26a7d463c..2ce65ca77 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -16,6 +16,7 @@ env_logger = "0.3" time = "0.1.34" rand = "0.3.13" heapsize = "0.3" +rustc-serialize = "0.3" [features] default = [] diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 6f28fc320..74541660d 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -70,6 +70,8 @@ use io::NetSyncIo; mod chain; mod io; mod range_collection; +// TODO [todr] Made public to suppress dead code warnings +pub mod transaction_queue; #[cfg(test)] mod tests; diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs new file mode 100644 index 000000000..341607afe --- /dev/null +++ b/sync/src/transaction_queue.rs @@ -0,0 +1,622 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +// TODO [todr] - own transactions should have higher priority + +//! Transaction Queue + +use std::vec::Vec; +use std::cmp::{Ordering}; +use std::collections::{HashMap, BTreeSet}; +use util::uint::{Uint, U256}; +use util::hash::{Address}; +use util::table::*; +use ethcore::transaction::*; + + +#[derive(Clone, Debug)] +struct VerifiedTransaction { + tx: SignedTransaction, + nonce_height: U256 +} + +impl VerifiedTransaction { + pub fn new(tx: SignedTransaction, nonce_height: U256) -> VerifiedTransaction { + VerifiedTransaction { + tx: tx, + nonce_height: nonce_height + } + } + + pub fn sender(&self) -> Address { + self.tx.sender().unwrap() + } +} + +impl Eq for VerifiedTransaction {} +impl PartialEq for VerifiedTransaction { + fn eq(&self, other: &VerifiedTransaction) -> bool { + self.cmp(other) == Ordering::Equal + } +} +impl PartialOrd for VerifiedTransaction { + fn partial_cmp(&self, other: &VerifiedTransaction) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for VerifiedTransaction { + fn cmp(&self, b: &VerifiedTransaction) -> Ordering { + // First check nonce_height + if self.nonce_height != b.nonce_height { + return self.nonce_height.cmp(&b.nonce_height); + } + + // Then compare gas_prices + let a_gas = self.tx.gas_price; + let b_gas = b.tx.gas_price; + if a_gas != b_gas { + return a_gas.cmp(&b_gas); + } + + // Compare nonce + let a_nonce = self.tx.nonce; + let b_nonce = b.tx.nonce; + if a_nonce != b_nonce { + return a_nonce.cmp(&b_nonce); + } + + // and senders + let a_sender = self.sender(); + let b_sender = b.sender(); + a_sender.cmp(&b_sender) + } +} + +struct TransactionsByPriorityAndAddress { + priority: BTreeSet, + address: Table, + limit: usize, +} + +impl TransactionsByPriorityAndAddress { + fn insert(&mut self, address: Address, nonce: U256, verified_tx: VerifiedTransaction) { + self.priority.insert(verified_tx.clone()); + self.address.insert(address, nonce, verified_tx); + } + + fn enforce_limit(&mut self) { + let len = self.priority.len(); + if len <= self.limit { + return; + } + + let to_remove : Vec = { + self.priority + .iter() + .skip(self.limit) + .map(|v_tx| v_tx.tx.clone()) + .collect() + }; + + for tx in to_remove { + self.remove(&tx); + } + } + + fn remove_by_address(&mut self, sender: &Address, nonce: &U256) -> Option { + if let Some(verified_tx) = self.address.remove(sender, nonce) { + self.priority.remove(&verified_tx); + return Some(verified_tx); + } + None + } + + fn remove(&mut self, tx: &SignedTransaction) -> Option { + // First find the transaction by address + let address = tx.sender().unwrap(); + self.remove_by_address(&address, &tx.nonce) + } + + fn clear(&mut self) { + self.priority.clear(); + self.address.clear(); + } +} + +#[derive(Debug)] +/// Current status of the queue +pub struct TransactionQueueStatus { + /// Number of pending transactions (ready to go to block) + pub pending: usize, + /// Number of future transactions (waiting for transactions with lower nonces first) + pub future: usize, +} + +/// TransactionQueue implementation +pub struct TransactionQueue { + /// Priority queue for transactions that can go to block + current: TransactionsByPriorityAndAddress, + /// Priority queue for transactions that has been received but are not yet valid to go to block + future: TransactionsByPriorityAndAddress, + /// Last nonce of transaction in current + last_nonces: HashMap, + /// First nonce of transaction in current (used to determine priority) + first_nonces: HashMap, +} + +impl TransactionQueue { + /// Creates new instance of this Queue + pub fn new() -> Self { + Self::with_limits(1024, 1024) + } + + /// Create new instance of this Queue with specified limits + pub fn with_limits(current_limit: usize, future_limit: usize) -> Self { + let current = TransactionsByPriorityAndAddress { + address: Table::new(), + priority: BTreeSet::new(), + limit: current_limit, + }; + let future = TransactionsByPriorityAndAddress { + address: Table::new(), + priority: BTreeSet::new(), + limit: future_limit, + }; + + TransactionQueue { + current: current, + future: future, + last_nonces: HashMap::new(), + first_nonces: HashMap::new(), + } + } + + /// Returns current status for this queue + pub fn status(&self) -> TransactionQueueStatus { + TransactionQueueStatus { + pending: self.current.priority.len(), + future: self.future.priority.len(), + } + } + + /// Adds all signed transactions to queue to be verified and imported + pub fn add_all(&mut self, txs: Vec, fetch_nonce: T) + where T: Fn(&Address) -> U256 { + for tx in txs.into_iter() { + self.add(tx, &fetch_nonce); + } + } + + /// Add signed transaction to queue to be verified and imported + pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) + where T: Fn(&Address) -> U256 { + self.import_tx(tx, fetch_nonce); + } + + /// Removes all transactions in given slice + /// + /// If gap is introduced marks subsequent transactions as future + pub fn remove_all(&mut self, txs: &[SignedTransaction]) { + for tx in txs { + self.remove(&tx); + } + } + + /// Removes transaction from queue. + /// + /// If gap is introduced marks subsequent transactions as future + pub fn remove(&mut self, tx: &SignedTransaction) { + // Remove from current + let removed = self.current.remove(tx); + if let Some(verified_tx) = removed { + let sender = verified_tx.sender(); + + // Are there any other transactions from this sender? + if !self.current.address.has_row(&sender) { + // Clear last & first nonces + self.last_nonces.remove(&sender); + self.first_nonces.remove(&sender); + return; + } + + // Let's find those with higher nonce (TODO [todr] optimize?) + let to_move_to_future = { + let row_map = self.current.address.row(&sender).unwrap(); + let tx_nonce = verified_tx.tx.nonce; + let mut to_future = Vec::new(); + let mut highest = U256::zero(); + let mut lowest = tx_nonce.clone(); + + // Search nonces to remove and track lowest and highest + for (nonce, _) in row_map.iter() { + if nonce > &tx_nonce { + to_future.push(nonce.clone()); + } else if nonce > &highest { + highest = nonce.clone(); + } else if nonce < &lowest { + lowest = nonce.clone(); + } + } + + // Update first_nonces and last_nonces + if highest == U256::zero() { + self.last_nonces.remove(&sender); + } else { + self.last_nonces.insert(sender.clone(), highest); + } + + if lowest == tx_nonce { + self.first_nonces.remove(&sender); + } else { + self.first_nonces.insert(sender.clone(), lowest); + } + + // return to future + to_future + }; + + for k in to_move_to_future { + if let Some(v) = self.current.remove_by_address(&sender, &k) { + self.future.insert(sender.clone(), v.tx.nonce, v); + } + } + self.future.enforce_limit(); + return; + } + + // Remove from future + { + let sender = tx.sender().unwrap(); + if let Some(_) = self.future.remove_by_address(&sender, &tx.nonce) { + return; + } + } + } + + /// Returns top transactions from the queue + pub fn top_transactions(&self, size: usize) -> Vec { + self.current.priority + .iter() + .take(size) + .map(|t| t.tx.clone()).collect() + } + + /// Removes all elements (in any state) from the queue + pub fn clear(&mut self) { + self.current.clear(); + self.future.clear(); + self.last_nonces.clear(); + self.first_nonces.clear(); + } + + fn move_future_txs(&mut self, address: Address, current_nonce: U256, first_nonce: U256) -> Option { + let mut current_nonce = current_nonce + U256::one(); + { + let txs_by_nonce = self.future.address.row_mut(&address); + if let None = txs_by_nonce { + return None; + } + let mut txs_by_nonce = txs_by_nonce.unwrap(); + + while let Some(tx) = txs_by_nonce.remove(¤t_nonce) { + // remove also from priority + self.future.priority.remove(&tx); + // Put to current + let height = current_nonce - first_nonce; + let verified_tx = VerifiedTransaction::new(tx.tx, U256::from(height)); + self.current.insert(address.clone(), verified_tx.tx.nonce, verified_tx); + current_nonce = current_nonce + U256::one(); + } + } + self.future.address.clear_if_empty(&address); + // Returns last inserted nonce + Some(current_nonce - U256::one()) + } + + fn import_tx(&mut self, tx: SignedTransaction, fetch_nonce: &T) + where T: Fn(&Address) -> U256 { + let nonce = tx.nonce; + let address = tx.sender().unwrap(); + + let next_nonce = U256::one() + self.last_nonces + .get(&address) + .cloned() + .unwrap_or_else(|| fetch_nonce(&address)); + + // Check height + if nonce > next_nonce { + let height = nonce - next_nonce; + let verified_tx = VerifiedTransaction::new(tx, height); + // We have a gap - put to future + self.future.insert(address, nonce, verified_tx); + self.future.enforce_limit(); + return; + } else if next_nonce > nonce { + // Droping transaction + return; + } + + let first_nonce = self.first_nonces + .get(&address) + .cloned() + .unwrap_or_else(|| nonce.clone()); + + let height = nonce - first_nonce; + let verified_tx = VerifiedTransaction::new(tx, height); + // Insert to current + self.current.insert(address.clone(), nonce, verified_tx); + // But maybe there are some more items waiting in future? + let new_last_nonce = self.move_future_txs(address.clone(), nonce, first_nonce); + self.first_nonces.insert(address.clone(), first_nonce); + self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); + // Enforce limit + self.current.enforce_limit(); + } +} + +#[cfg(test)] +mod test { + extern crate rustc_serialize; + use self::rustc_serialize::hex::FromHex; + + use util::crypto::KeyPair; + use util::uint::{U256, Uint}; + use util::hash::{Address}; + use ethcore::transaction::*; + use super::*; + + fn new_unsigned_tx(nonce: U256) -> Transaction { + Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: nonce + } + } + + fn new_tx() -> SignedTransaction { + let keypair = KeyPair::create().unwrap(); + new_unsigned_tx(U256::from(123)).sign(&keypair.secret()) + } + + fn default_nonce(_address: &Address) -> U256 { + U256::from(122) + } + + fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) { + let keypair = KeyPair::create().unwrap(); + let secret = &keypair.secret(); + let nonce = U256::from(123); + let tx = new_unsigned_tx(nonce); + let tx2 = new_unsigned_tx(nonce + second_nonce); + + (tx.sign(secret), tx2.sign(secret)) + } + + #[test] + fn should_import_tx() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + + // when + txq.add(tx, &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 1); + } + + #[test] + fn should_import_txs_from_same_sender() { + // given + let mut txq = TransactionQueue::new(); + + let (tx, tx2) = new_txs(U256::from(1)); + + // when + txq.add(tx.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce); + + // then + let top = txq.top_transactions(5); + assert_eq!(top[0], tx); + assert_eq!(top[1], tx2); + assert_eq!(top.len(), 2); + } + + #[test] + fn should_put_transaction_to_futures_if_gap_detected() { + // given + let mut txq = TransactionQueue::new(); + + let (tx, tx2) = new_txs(U256::from(2)); + + // when + txq.add(tx.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 1); + assert_eq!(stats.future, 1); + let top = txq.top_transactions(5); + assert_eq!(top.len(), 1); + assert_eq!(top[0], tx); + } + + #[test] + fn should_move_transactions_if_gap_filled() { + // given + let mut txq = TransactionQueue::new(); + let kp = KeyPair::create().unwrap(); + let secret = kp.secret(); + let tx = new_unsigned_tx(U256::from(123)).sign(&secret); + let tx1 = new_unsigned_tx(U256::from(124)).sign(&secret); + let tx2 = new_unsigned_tx(U256::from(125)).sign(&secret); + + txq.add(tx, &default_nonce); + assert_eq!(txq.status().pending, 1); + txq.add(tx2, &default_nonce); + assert_eq!(txq.status().future, 1); + + // when + txq.add(tx1, &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 3); + assert_eq!(stats.future, 0); + } + + #[test] + fn should_remove_transaction() { + // given + let mut txq2 = TransactionQueue::new(); + let (tx, tx2) = new_txs(U256::from(3)); + txq2.add(tx.clone(), &default_nonce); + txq2.add(tx2.clone(), &default_nonce); + assert_eq!(txq2.status().pending, 1); + assert_eq!(txq2.status().future, 1); + + // when + txq2.remove(&tx); + txq2.remove(&tx2); + + + // then + let stats = txq2.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + + #[test] + fn should_move_transactions_to_future_if_gap_introduced() { + // given + let mut txq = TransactionQueue::new(); + let (tx, tx2) = new_txs(U256::from(1)); + let tx3 = new_tx(); + txq.add(tx2.clone(), &default_nonce); + assert_eq!(txq.status().future, 1); + txq.add(tx3.clone(), &default_nonce); + txq.add(tx.clone(), &default_nonce); + assert_eq!(txq.status().pending, 3); + + // when + txq.remove(&tx); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 1); + assert_eq!(stats.pending, 1); + } + + #[test] + fn should_clear_queue() { + // given + let mut txq = TransactionQueue::new(); + let (tx, tx2) = new_txs(U256::one()); + + // add + txq.add(tx2.clone(), &default_nonce); + txq.add(tx.clone(), &default_nonce); + let stats = txq.status(); + assert_eq!(stats.pending, 2); + + // when + txq.clear(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + } + + #[test] + fn should_drop_old_transactions_when_hitting_the_limit() { + // given + let mut txq = TransactionQueue::with_limits(1, 1); + let (tx, tx2) = new_txs(U256::one()); + txq.add(tx.clone(), &default_nonce); + assert_eq!(txq.status().pending, 1); + + // when + txq.add(tx2.clone(), &default_nonce); + + // then + let t = txq.top_transactions(2); + assert_eq!(txq.status().pending, 1); + assert_eq!(t.len(), 1); + assert_eq!(t[0], tx); + } + + #[test] + fn should_limit_future_transactions() { + let mut txq = TransactionQueue::with_limits(10, 1); + let (tx1, tx2) = new_txs(U256::from(4)); + let (tx3, tx4) = new_txs(U256::from(4)); + txq.add(tx1.clone(), &default_nonce); + txq.add(tx3.clone(), &default_nonce); + assert_eq!(txq.status().pending, 2); + + // when + txq.add(tx2.clone(), &default_nonce); + assert_eq!(txq.status().future, 1); + txq.add(tx4.clone(), &default_nonce); + + // then + assert_eq!(txq.status().future, 1); + } + + #[test] + fn should_drop_transactions_with_old_nonces() { + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + let last_nonce = tx.nonce.clone(); + let fetch_last_nonce = |_a: &Address| last_nonce; + + // when + txq.add(tx, &fetch_last_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + + #[test] + fn should_accept_same_transaction_twice() { + // given + let mut txq = TransactionQueue::new(); + let (tx1, tx2) = new_txs(U256::from(1)); + txq.add(tx1.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce); + assert_eq!(txq.status().pending, 2); + + // when + txq.remove(&tx1); + assert_eq!(txq.status().future, 1); + txq.add(tx1.clone(), &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 2); + assert_eq!(stats.future, 0); + + } + +} From 30e7ac8d6d4a9f0f6553d48bedd82083266aaa7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 1 Mar 2016 21:54:53 +0100 Subject: [PATCH 305/753] Fixing trivial warnings --- util/src/table.rs | 2 +- util/src/uint.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/util/src/table.rs b/util/src/table.rs index f04a498f8..e41209608 100644 --- a/util/src/table.rs +++ b/util/src/table.rs @@ -111,7 +111,7 @@ impl Table /// /// Returns previous value (if any) pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option { - self.map.entry(row).or_insert_with(|| HashMap::new()).insert(col, val) + self.map.entry(row).or_insert_with(HashMap::new).insert(col, val) } } diff --git a/util/src/uint.rs b/util/src/uint.rs index 88256d5f2..068456334 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -1982,6 +1982,7 @@ mod tests { #[test] + #[cfg_attr(feature = "dev", allow(cyclomatic_complexity))] fn u256_multi_full_mul() { let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0])); assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result); From 083747dc674c63739cdde254ca9731e2fb784343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 1 Mar 2016 22:03:29 +0100 Subject: [PATCH 306/753] Lowering complexity of request_blocks --- sync/src/chain.rs | 159 ++++++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 77 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 6a7add27f..1d90e2d03 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -249,14 +249,14 @@ impl ChainSync { blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), - mem_used: + mem_used: // TODO: https://github.com/servo/heapsize/pull/50 - // self.downloading_hashes.heap_size_of_children() - //+ self.downloading_bodies.heap_size_of_children() - //+ self.downloading_hashes.heap_size_of_children() - self.headers.heap_size_of_children() - + self.bodies.heap_size_of_children() - + self.peers.heap_size_of_children() + // self.downloading_hashes.heap_size_of_children() + //+ self.downloading_bodies.heap_size_of_children() + //+ self.downloading_hashes.heap_size_of_children() + self.headers.heap_size_of_children() + + self.bodies.heap_size_of_children() + + self.peers.heap_size_of_children() + self.header_ids.heap_size_of_children(), } } @@ -635,16 +635,7 @@ impl ChainSync { match self.last_imported_block { None => 0, Some(x) => x } } - /// Find some headers or blocks to download for a peer. - fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId, ignore_others: bool) { - self.clear_peer_download(peer_id); - - if io.chain().queue_info().is_full() { - self.pause_sync(); - return; - } - - // check to see if we need to download any block bodies first + fn find_block_bodies_hashes_to_request(&self, ignore_others: bool) -> (Vec, Vec) { let mut needed_bodies: Vec = Vec::new(); let mut needed_numbers: Vec = Vec::new(); @@ -664,74 +655,88 @@ impl ChainSync { } } } + (needed_bodies, needed_numbers) + } + + /// Find some headers or blocks to download for a peer. + fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId, ignore_others: bool) { + self.clear_peer_download(peer_id); + + if io.chain().queue_info().is_full() { + self.pause_sync(); + return; + } + + // check to see if we need to download any block bodies first + let (needed_bodies, needed_numbers) = self.find_block_bodies_hashes_to_request(ignore_others); if !needed_bodies.is_empty() { let (head, _) = self.headers.range_iter().next().unwrap(); if needed_numbers.first().unwrap() - head > self.max_download_ahead_blocks as BlockNumber { trace!(target: "sync", "{}: Stalled download ({} vs {}), helping with downloading block bodies", peer_id, needed_numbers.first().unwrap(), head); self.request_blocks(io, peer_id, true); - return; + } else { + self.downloading_bodies.extend(needed_numbers.iter()); + replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers); + self.request_bodies(io, peer_id, needed_bodies); + } + return; + } + + // check if need to download headers + let mut start = 0; + if !self.have_common_block { + // download backwards until common block is found 1 header at a time + let chain_info = io.chain().chain_info(); + start = chain_info.best_block_number; + if !self.headers.is_empty() { + start = min(start, self.headers.range_iter().next().unwrap().0 - 1); + } + if start == 0 { + self.have_common_block = true; //reached genesis + self.last_imported_hash = Some(chain_info.genesis_hash); + self.last_imported_block = Some(0); + } + } + if self.have_common_block { + let mut headers: Vec = Vec::new(); + let mut prev = self.current_base_block() + 1; + let head = self.headers.range_iter().next().map(|(h, _)| h); + for (next, ref items) in self.headers.range_iter() { + if !headers.is_empty() { + break; + } + if next <= prev { + prev = next + items.len() as BlockNumber; + continue; + } + let mut block = prev; + while block < next && headers.len() < MAX_HEADERS_TO_REQUEST { + if ignore_others || !self.downloading_headers.contains(&(block as BlockNumber)) { + headers.push(block as BlockNumber); + } + block += 1; + } + prev = next + items.len() as BlockNumber; + } + + if !headers.is_empty() { + start = headers[0]; + if head.is_some() && start > head.unwrap() && start - head.unwrap() > self.max_download_ahead_blocks as BlockNumber { + trace!(target: "sync", "{}: Stalled download ({} vs {}), helping with downloading headers", peer_id, start, head.unwrap()); + self.request_blocks(io, peer_id, true); + return; + } + let count = headers.len(); + self.downloading_headers.extend(headers.iter()); + replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, headers); + assert!(!self.headers.have_item(&start)); + self.request_headers_by_number(io, peer_id, start, count, 0, false); } - self.downloading_bodies.extend(needed_numbers.iter()); - replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers); - self.request_bodies(io, peer_id, needed_bodies); } else { - // check if need to download headers - let mut start = 0; - if !self.have_common_block { - // download backwards until common block is found 1 header at a time - let chain_info = io.chain().chain_info(); - start = chain_info.best_block_number; - if !self.headers.is_empty() { - start = min(start, self.headers.range_iter().next().unwrap().0 - 1); - } - if start == 0 { - self.have_common_block = true; //reached genesis - self.last_imported_hash = Some(chain_info.genesis_hash); - self.last_imported_block = Some(0); - } - } - if self.have_common_block { - let mut headers: Vec = Vec::new(); - let mut prev = self.current_base_block() + 1; - let head = self.headers.range_iter().next().map(|(h, _)| h); - for (next, ref items) in self.headers.range_iter() { - if !headers.is_empty() { - break; - } - if next <= prev { - prev = next + items.len() as BlockNumber; - continue; - } - let mut block = prev; - while block < next && headers.len() < MAX_HEADERS_TO_REQUEST { - if ignore_others || !self.downloading_headers.contains(&(block as BlockNumber)) { - headers.push(block as BlockNumber); - } - block += 1; - } - prev = next + items.len() as BlockNumber; - } - - if !headers.is_empty() { - start = headers[0]; - if head.is_some() && start > head.unwrap() && start - head.unwrap() > self.max_download_ahead_blocks as BlockNumber { - trace!(target: "sync", "{}: Stalled download ({} vs {}), helping with downloading headers", peer_id, start, head.unwrap()); - self.request_blocks(io, peer_id, true); - return; - } - let count = headers.len(); - self.downloading_headers.extend(headers.iter()); - replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, headers); - assert!(!self.headers.have_item(&start)); - self.request_headers_by_number(io, peer_id, start, count, 0, false); - } - } - else { - // continue search for common block - self.downloading_headers.insert(start); - self.request_headers_by_number(io, peer_id, start, 1, 0, false); - } + // continue search for common block + self.downloading_headers.insert(start); + self.request_headers_by_number(io, peer_id, start, 1, 0, false); } } From 7565625ce042cfc8ce328f9387d8732da48cc4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 1 Mar 2016 22:30:23 +0100 Subject: [PATCH 307/753] Integrating TransactionQueue with client --- Cargo.lock | 19 +++++++++ ethcore/src/client.rs | 7 +++ sync/Cargo.toml | 1 + sync/src/chain.rs | 89 ++++++++++++++++++++++++++++++++++----- sync/src/lib.rs | 14 ++++-- sync/src/tests/helpers.rs | 4 ++ 6 files changed, 120 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e558606eb..845c493fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,6 +125,14 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "deque" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "docopt" version = "0.6.78" @@ -259,6 +267,7 @@ dependencies = [ "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -629,6 +638,16 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rayon" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex" version = "0.1.54" diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index f2894decb..611561c50 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -123,6 +123,9 @@ pub trait BlockChainClient : Sync + Send { /// Get block total difficulty. fn block_total_difficulty(&self, id: BlockId) -> Option; + /// Get address nonce. + fn nonce(&self, address: &Address) -> U256; + /// Get address code. fn code(&self, address: &Address) -> Option; @@ -445,6 +448,10 @@ impl BlockChainClient for Client { Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) } + fn nonce(&self, address: &Address) -> U256 { + self.state().nonce(address) + } + fn code(&self, address: &Address) -> Option { self.state().code(address) } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 2ce65ca77..993f07a65 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -17,6 +17,7 @@ time = "0.1.34" rand = "0.3.13" heapsize = "0.3" rustc-serialize = "0.3" +rayon = "0.3.1" [features] default = [] diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 6a7add27f..fa033813e 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -30,14 +30,17 @@ /// use util::*; +use rayon::prelude::*; use std::mem::{replace}; -use ethcore::views::{HeaderView}; +use ethcore::views::{HeaderView, BlockView}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId}; use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::block::Block; +use ethcore::transaction::SignedTransaction; use io::SyncIo; +use transaction_queue::TransactionQueue; use time; use super::SyncConfig; @@ -209,6 +212,8 @@ pub struct ChainSync { max_download_ahead_blocks: usize, /// Network ID network_id: U256, + /// Transactions Queue + transaction_queue: Mutex, } type RlpResponseResult = Result, PacketDecodeError>; @@ -234,6 +239,7 @@ impl ChainSync { last_send_block_number: 0, max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, + transaction_queue: Mutex::new(TransactionQueue::new()), } } @@ -249,14 +255,14 @@ impl ChainSync { blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), - mem_used: + mem_used: // TODO: https://github.com/servo/heapsize/pull/50 - // self.downloading_hashes.heap_size_of_children() - //+ self.downloading_bodies.heap_size_of_children() - //+ self.downloading_hashes.heap_size_of_children() - self.headers.heap_size_of_children() - + self.bodies.heap_size_of_children() - + self.peers.heap_size_of_children() + // self.downloading_hashes.heap_size_of_children() + //+ self.downloading_bodies.heap_size_of_children() + //+ self.downloading_hashes.heap_size_of_children() + self.headers.heap_size_of_children() + + self.bodies.heap_size_of_children() + + self.peers.heap_size_of_children() + self.header_ids.heap_size_of_children(), } } @@ -292,6 +298,7 @@ impl ChainSync { self.starting_block = 0; self.highest_block = None; self.have_common_block = false; + self.transaction_queue.lock().unwrap().clear(); self.starting_block = io.chain().chain_info().best_block_number; self.state = SyncState::NotSynced; } @@ -913,8 +920,16 @@ impl ChainSync { } } /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, _io: &mut SyncIo, _peer_id: PeerId, _r: &UntrustedRlp) -> Result<(), PacketDecodeError> { - Ok(()) + fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + let chain = io.chain(); + let item_count = r.item_count(); + trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count); + let fetch_latest_nonce = |a : &Address| chain.nonce(a); + for i in 0..item_count { + let tx: SignedTransaction = try!(r.val_at(i)); + self.transaction_queue.lock().unwrap().add(tx, &fetch_latest_nonce); + } + Ok(()) } /// Send Status message @@ -1242,6 +1257,34 @@ impl ChainSync { } self.last_send_block_number = chain.best_block_number; } + + /// called when block is imported to chain, updates transactions queue + pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], bad: &[H256]) { + fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { + let block = chain + .block(BlockId::Hash(hash.clone())) + .expect("Expected in-chain blocks."); + let block = BlockView::new(&block); + block.transactions() + }; + + let chain = io.chain(); + let good = good.par_iter().map(|h| fetch_transactions(chain, h)); + let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); + + good.for_each(|txs| { + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.remove_all(&txs); + }); + bad.for_each(|txs| { + // populate sender + for tx in &txs { + let _sender = tx.sender(); + } + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.add_all(txs, |a| chain.nonce(a)); + }); + } } #[cfg(test)] @@ -1571,6 +1614,32 @@ mod tests { assert!(result.is_ok()); } + #[test] + fn should_add_transactions_to_queue() { + // given + let mut client = TestBlockChainClient::new(); + // client.add_blocks(98, BlocksWith::Uncle); + // client.add_blocks(1, BlocksWith::UncleAndTransaction); + // client.add_blocks(1, BlocksWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let bad_blocks = vec![client.block_hash_delta_minus(1)]; + + let mut queue = VecDeque::new(); + let io = TestIo::new(&mut client, &mut queue, None); + + // when + sync.chain_new_blocks(&io, &[], &good_blocks); + assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); + sync.chain_new_blocks(&io, &good_blocks, &bad_blocks); + + // then + let status = sync.transaction_queue.lock().unwrap().status(); + assert_eq!(status.pending, 1); + assert_eq!(status.future, 0); + } + #[test] fn returns_requested_block_headers() { let mut client = TestBlockChainClient::new(); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 74541660d..44f3f02e0 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -54,6 +54,7 @@ extern crate ethcore; extern crate env_logger; extern crate time; extern crate rand; +extern crate rayon; #[macro_use] extern crate heapsize; @@ -70,8 +71,7 @@ use io::NetSyncIo; mod chain; mod io; mod range_collection; -// TODO [todr] Made public to suppress dead code warnings -pub mod transaction_queue; +mod transaction_queue; #[cfg(test)] mod tests; @@ -153,8 +153,14 @@ impl NetworkProtocolHandler for EthSync { } fn message(&self, io: &NetworkContext, message: &SyncMessage) { - if let SyncMessage::BlockVerified = *message { - self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); + match *message { + SyncMessage::BlockVerified => { + self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); + }, + SyncMessage::NewChainBlocks { ref good, ref bad } => { + let sync_io = NetSyncIo::new(io, self.chain.deref()); + self.sync.write().unwrap().chain_new_blocks(&sync_io, good, bad); + } } } } diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index b788e0c2a..302836920 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -105,6 +105,10 @@ impl BlockChainClient for TestBlockChainClient { Some(U256::zero()) } + fn nonce(&self, _address: &Address) -> U256 { + U256::zero() + } + fn code(&self, _address: &Address) -> Option { unimplemented!(); } From c6934431d12af045364bb9256d45305969ccee67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 25 Feb 2016 11:49:12 +0100 Subject: [PATCH 308/753] Adding test for sync.chain_new_blocks. --- sync/src/chain.rs | 33 ++++++++++---------- sync/src/tests/chain.rs | 51 ++++++++++++++++--------------- sync/src/tests/helpers.rs | 57 +++++++++++++++++++++++++++-------- sync/src/transaction_queue.rs | 1 + 4 files changed, 88 insertions(+), 54 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index fa033813e..9edab791a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1425,7 +1425,7 @@ mod tests { #[test] fn finds_lagging_peers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); let io = TestIo::new(&mut client, &mut queue, None); @@ -1438,7 +1438,7 @@ mod tests { #[test] fn calculates_tree_for_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(15, false); + client.add_blocks(15, BlocksWith::Uncle); let start = client.block_hash_delta_minus(4); let end = client.block_hash_delta_minus(2); @@ -1455,7 +1455,7 @@ mod tests { #[test] fn sends_new_hashes_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); @@ -1475,7 +1475,7 @@ mod tests { #[test] fn sends_latest_block_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); @@ -1495,7 +1495,7 @@ mod tests { #[test] fn handles_peer_new_block_mallformed() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, BlocksWith::Uncle); let block_data = get_dummy_block(11, client.chain_info().best_block_hash); @@ -1513,7 +1513,7 @@ mod tests { #[test] fn handles_peer_new_block() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, BlocksWith::Uncle); let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); @@ -1531,7 +1531,7 @@ mod tests { #[test] fn handles_peer_new_block_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1547,7 +1547,7 @@ mod tests { #[test] fn handles_peer_new_hashes() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1563,7 +1563,7 @@ mod tests { #[test] fn handles_peer_new_hashes_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1581,7 +1581,7 @@ mod tests { #[test] fn hashes_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); @@ -1600,7 +1600,7 @@ mod tests { #[test] fn block_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, BlocksWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let best_hash = client.chain_info().best_block_hash.clone(); @@ -1618,9 +1618,9 @@ mod tests { fn should_add_transactions_to_queue() { // given let mut client = TestBlockChainClient::new(); - // client.add_blocks(98, BlocksWith::Uncle); - // client.add_blocks(1, BlocksWith::UncleAndTransaction); - // client.add_blocks(1, BlocksWith::Transaction); + client.add_blocks(98, BlocksWith::Uncle); + client.add_blocks(1, BlocksWith::UncleAndTransaction); + client.add_blocks(1, BlocksWith::Transaction); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let good_blocks = vec![client.block_hash_delta_minus(2)]; @@ -1631,6 +1631,7 @@ mod tests { // when sync.chain_new_blocks(&io, &[], &good_blocks); + assert_eq!(sync.transaction_queue.lock().unwrap().status().future, 0); assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); sync.chain_new_blocks(&io, &good_blocks, &bad_blocks); @@ -1643,7 +1644,7 @@ mod tests { #[test] fn returns_requested_block_headers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, BlocksWith::Uncle); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); @@ -1667,7 +1668,7 @@ mod tests { #[test] fn returns_requested_block_headers_reverse() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, BlocksWith::Uncle); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 1dd9a1e78..78663aa16 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -24,8 +24,8 @@ use super::helpers::*; fn two_peers() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, BlocksWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, BlocksWith::Uncle); net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); @@ -35,8 +35,8 @@ fn two_peers() { fn status_after_sync() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, BlocksWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, BlocksWith::Uncle); net.sync(); let status = net.peer(0).sync.status(); assert_eq!(status.state, SyncState::Idle); @@ -45,8 +45,8 @@ fn status_after_sync() { #[test] fn takes_few_steps() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(100, false); - net.peer_mut(2).chain.add_blocks(100, false); + net.peer_mut(1).chain.add_blocks(100, BlocksWith::Uncle); + net.peer_mut(2).chain.add_blocks(100, BlocksWith::Uncle); let total_steps = net.sync(); assert!(total_steps < 7); } @@ -56,8 +56,9 @@ fn empty_blocks() { ::env_logger::init().ok(); let mut net = TestNet::new(3); for n in 0..200 { - net.peer_mut(1).chain.add_blocks(5, n % 2 == 0); - net.peer_mut(2).chain.add_blocks(5, n % 2 == 0); + let with = if n % 2 == 0 { BlocksWith::Nothing } else { BlocksWith::Uncle }; + net.peer_mut(1).chain.add_blocks(5, with.clone()); + net.peer_mut(2).chain.add_blocks(5, with); } net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); @@ -68,14 +69,14 @@ fn empty_blocks() { fn forked() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(0).chain.add_blocks(300, false); - net.peer_mut(1).chain.add_blocks(300, false); - net.peer_mut(2).chain.add_blocks(300, false); - net.peer_mut(0).chain.add_blocks(100, true); //fork - net.peer_mut(1).chain.add_blocks(200, false); - net.peer_mut(2).chain.add_blocks(200, false); - net.peer_mut(1).chain.add_blocks(100, false); //fork between 1 and 2 - net.peer_mut(2).chain.add_blocks(10, true); + net.peer_mut(0).chain.add_blocks(300, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(300, BlocksWith::Uncle); + net.peer_mut(2).chain.add_blocks(300, BlocksWith::Uncle); + net.peer_mut(0).chain.add_blocks(100, BlocksWith::Nothing); //fork + net.peer_mut(1).chain.add_blocks(200, BlocksWith::Uncle); + net.peer_mut(2).chain.add_blocks(200, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(100, BlocksWith::Uncle); //fork between 1 and 2 + net.peer_mut(2).chain.add_blocks(10, BlocksWith::Nothing); // peer 1 has the best chain of 601 blocks let peer1_chain = net.peer(1).chain.numbers.read().unwrap().clone(); net.sync(); @@ -87,8 +88,8 @@ fn forked() { #[test] fn restart() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, BlocksWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, BlocksWith::Uncle); net.sync_steps(8); @@ -109,8 +110,8 @@ fn status_empty() { #[test] fn status_packet() { let mut net = TestNet::new(2); - net.peer_mut(0).chain.add_blocks(100, false); - net.peer_mut(1).chain.add_blocks(1, false); + net.peer_mut(0).chain.add_blocks(100, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(1, BlocksWith::Uncle); net.start(); @@ -123,10 +124,10 @@ fn status_packet() { #[test] fn propagade_hashes() { let mut net = TestNet::new(6); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, false); + net.peer_mut(0).chain.add_blocks(10, BlocksWith::Uncle); net.sync(); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -149,10 +150,10 @@ fn propagade_hashes() { #[test] fn propagade_blocks() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, false); + net.peer_mut(0).chain.add_blocks(10, BlocksWith::Uncle); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -164,7 +165,7 @@ fn propagade_blocks() { #[test] fn restart_on_malformed_block() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); net.peer_mut(1).chain.corrupt_block(6); net.sync_steps(10); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 302836920..bb980e3f9 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -22,7 +22,7 @@ use io::SyncIo; use chain::ChainSync; use ::SyncConfig; use ethcore::receipt::Receipt; -use ethcore::transaction::LocalizedTransaction; +use ethcore::transaction::{LocalizedTransaction, Transaction, Action}; use ethcore::filter::Filter; use ethcore::log_entry::LocalizedLogEntry; @@ -34,6 +34,14 @@ pub struct TestBlockChainClient { pub difficulty: RwLock, } +#[derive(Clone)] +pub enum BlocksWith { + Nothing, + Uncle, + Transaction, + UncleAndTransaction +} + impl TestBlockChainClient { pub fn new() -> TestBlockChainClient { @@ -44,30 +52,53 @@ impl TestBlockChainClient { last_hash: RwLock::new(H256::new()), difficulty: RwLock::new(From::from(0)), }; - client.add_blocks(1, true); // add genesis block + client.add_blocks(1, BlocksWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } - pub fn add_blocks(&mut self, count: usize, empty: bool) { + pub fn add_blocks(&mut self, count: usize, with: BlocksWith) { let len = self.numbers.read().unwrap().len(); for n in len..(len + count) { let mut header = BlockHeader::new(); header.difficulty = From::from(n); header.parent_hash = self.last_hash.read().unwrap().clone(); header.number = n as BlockNumber; - let mut uncles = RlpStream::new_list(if empty {0} else {1}); - if !empty { - let mut uncle_header = BlockHeader::new(); - uncle_header.difficulty = From::from(n); - uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); - uncle_header.number = n as BlockNumber; - uncles.append(&uncle_header); - header.uncles_hash = uncles.as_raw().sha3(); - } + let uncles = match with { + BlocksWith::Uncle | BlocksWith::UncleAndTransaction => { + let mut uncles = RlpStream::new_list(1); + let mut uncle_header = BlockHeader::new(); + uncle_header.difficulty = From::from(n); + uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); + uncle_header.number = n as BlockNumber; + uncles.append(&uncle_header); + header.uncles_hash = uncles.as_raw().sha3(); + uncles + }, + _ => RlpStream::new_list(0) + }; + let txs = match with { + BlocksWith::Transaction | BlocksWith::UncleAndTransaction => { + let mut txs = RlpStream::new_list(1); + let keypair = KeyPair::create().unwrap(); + let tx = Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::one() + }; + let signed_tx = tx.sign(&keypair.secret()); + txs.append(&signed_tx); + txs.out() + }, + _ => rlp::NULL_RLP.to_vec() + }; + let mut rlp = RlpStream::new_list(3); rlp.append(&header); - rlp.append_raw(&rlp::NULL_RLP, 1); + rlp.append_raw(&txs, 1); rlp.append_raw(uncles.as_raw(), 1); self.import_block(rlp.as_raw().to_vec()).unwrap(); } diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 341607afe..fa6026477 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -346,6 +346,7 @@ impl TransactionQueue { return; } else if next_nonce > nonce { // Droping transaction + trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); return; } From c889d9b3eb21c1b54989d741c6b34bed4bfc30ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 25 Feb 2016 16:58:18 +0100 Subject: [PATCH 309/753] Exposing transaction queue pending in RPC --- rpc/src/v1/impls/eth.rs | 13 ++++++++++++- rpc/src/v1/traits/eth.rs | 13 ++++++++----- sync/src/chain.rs | 3 +++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 00bce5437..6d66a2c6d 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -152,7 +152,7 @@ impl Eth for EthClient { } } - fn block_transaction_count(&self, params: Params) -> Result { + fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), @@ -160,6 +160,17 @@ impl Eth for EthClient { }) } + fn block_transaction_count_by_number(&self, params: Params) -> Result { + from_params::<(BlockNumber,)>(params) + .and_then(|(block_number,)| match block_number { + BlockNumber::Pending => to_value(&take_weak!(self.sync).status().transaction_queue_pending), + _ => match take_weak!(self.client).block(block_number.into()) { + Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), + None => Ok(Value::Null) + } + }) + } + fn block_uncles_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index d2aeb0f9e..8c24dd38c 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -55,12 +55,15 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns block with given number. fn block_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } - + /// Returns the number of transactions sent from given address at given time (block number). fn transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns the number of transactions in a block. - fn block_transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns the number of transactions in a block given block hash. + fn block_transaction_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns the number of transactions in a block given block number. + fn block_transaction_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns the number of uncles in a given block. fn block_uncles_count(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -130,8 +133,8 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_balance", Eth::balance); delegate.add_method("eth_getStorageAt", Eth::storage_at); delegate.add_method("eth_getTransactionCount", Eth::transaction_count); - delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count); - delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count); + delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count_by_hash); + delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count_by_number); delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count); delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count); delegate.add_method("eth_code", Eth::code_at); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 9edab791a..90f7b0d2a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -140,6 +140,8 @@ pub struct SyncStatus { pub num_active_peers: usize, /// Heap memory used in bytes pub mem_used: usize, + /// Number of pending transactions in queue + pub transaction_queue_pending: usize, } #[derive(PartialEq, Eq, Debug, Clone)] @@ -255,6 +257,7 @@ impl ChainSync { blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), + transaction_queue_pending: self.transaction_queue.lock().unwrap().status().pending, mem_used: // TODO: https://github.com/servo/heapsize/pull/50 // self.downloading_hashes.heap_size_of_children() From 929f44fe4f62910fc0eba95257953b09ccd52b24 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 00:34:38 +0100 Subject: [PATCH 310/753] Tests for Client sealing. --- ethcore/src/engine.rs | 9 +++++++-- ethcore/src/ethereum/ethash.rs | 3 ++- ethcore/src/tests/client.rs | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index a05c78ff5..6806fcce3 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -81,9 +81,14 @@ pub trait Engine : Sync + Send { self.verify_block_basic(header, None).and_then(|_| self.verify_block_unordered(header, None)) } - /// Don't forget to call Super::populateFromParent when subclassing & overriding. + /// Don't forget to call Super::populate_from_parent when subclassing & overriding. // TODO: consider including State in the params. - fn populate_from_parent(&self, _header: &mut Header, _parent: &Header) {} + fn populate_from_parent(&self, header: &mut Header, parent: &Header) { + header.parent_hash = parent.hash; + header.difficulty = parent.difficulty; + header.gas_limit = parent.gas_limit; + header.number = parent.number + 1; + } // TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic // from Spec into here and removing the Spec::builtins field. diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 6dabe558f..bf0c1d188 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -144,7 +144,8 @@ impl Engine for Ethash { let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty( &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64(), - &Ethash::to_ethash(header.mix_hash()) ))); + &Ethash::to_ethash(header.mix_hash()) + ))); if difficulty < header.difficulty { return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty }))); } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 83df81fa2..65c9d7358 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use client::{BlockChainClient, Client, ClientConfig, BlockId}; +use block::IsBlock; use tests::helpers::*; use common::*; use devtools::*; @@ -106,3 +107,22 @@ fn can_collect_garbage() { client.tick(); assert!(client.blockchain_cache_info().blocks < 100 * 1024); } + +#[test] +fn can_mine() { + let dummy_blocks = get_good_dummy_block_seq(2); + let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); + let client = client_result.reference(); + let b = client.sealing_block(); + let pow_hash = { + let u = b.lock().unwrap(); + match *u { + Some(ref b) => { + assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); + b.hash() + } + None => { panic!(); } + } + }; + assert!(client.submit_seal(pow_hash, vec![]).is_ok()); +} \ No newline at end of file From 30c68204377742dbd7cda4bd5ac3114713de5cb1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 00:52:18 +0100 Subject: [PATCH 311/753] Refactor and cleanup. --- ethcore/src/block.rs | 9 +++++---- ethcore/src/engine.rs | 3 +-- ethcore/src/ethereum/ethash.rs | 2 +- rpc/src/v1/impls/web3.rs | 2 +- util/src/misc.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 0ca6e88be..f5788baba 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -178,11 +178,12 @@ impl<'x> OpenBlock<'x> { last_hashes: last_hashes, }; - r.block.base.header.set_number(parent.number() + 1); - r.block.base.header.set_author(author); - r.block.base.header.set_extra_data(extra_data); + r.block.base.header.parent_hash = parent.hash(); + r.block.base.header.number = parent.number + 1; + r.block.base.header.author = author; r.block.base.header.set_timestamp_now(parent.timestamp()); - r.block.base.header.set_parent_hash(parent.hash()); + r.block.base.header.extra_data = extra_data; + r.block.base.header.note_dirty(); engine.populate_from_parent(&mut r.block.base.header, parent); engine.on_new_block(&mut r.block); diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index 6806fcce3..d607ce2e2 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -84,10 +84,9 @@ pub trait Engine : Sync + Send { /// Don't forget to call Super::populate_from_parent when subclassing & overriding. // TODO: consider including State in the params. fn populate_from_parent(&self, header: &mut Header, parent: &Header) { - header.parent_hash = parent.hash; header.difficulty = parent.difficulty; header.gas_limit = parent.gas_limit; - header.number = parent.number + 1; + header.note_dirty(); } // TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index bf0c1d188..f9810b964 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -104,7 +104,7 @@ impl Engine for Ethash { max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1) + (header.gas_used * x!(6) / x!(5)) / bound_divisor) } }; - + header.note_dirty(); // info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit); } diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index 0a237d56b..4d31f73ae 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -31,7 +31,7 @@ impl Web3 for Web3Client { fn client_version(&self, params: Params) -> Result { match params { Params::None => { - Ok(Value::String(version())), + Ok(Value::String(version().to_owned().replace("Parity/", "Parity//"))), } _ => Err(Error::invalid_params()) } diff --git a/util/src/misc.rs b/util/src/misc.rs index 6cd506d02..39ccbf2da 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -70,7 +70,7 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { - format!("Parity//v{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) + format!("Parity/v{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) } /// Get the standard version data for this software. From 324e070581305ded5b9c40942f86837756f2116d Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 2 Mar 2016 01:24:06 +0100 Subject: [PATCH 312/753] Reverted some changes --- ethcore/src/block_queue.rs | 3 +-- util/sha3/build.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index f61eb565d..de411c6e2 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -302,8 +302,7 @@ impl BlockQueue { if self.processing.read().unwrap().contains(&h) { return Err(ImportError::AlreadyQueued); } - } - { + let mut bad = self.verification.bad.lock().unwrap(); if bad.contains(&h) { return Err(ImportError::Bad(None)); diff --git a/util/sha3/build.rs b/util/sha3/build.rs index 9eb36fdb9..bbe16d720 100644 --- a/util/sha3/build.rs +++ b/util/sha3/build.rs @@ -21,6 +21,6 @@ extern crate gcc; fn main() { - gcc::Config::new().file("src/tinykeccak.c").flag("-O3").compile("libtinykeccak.a"); + gcc::compile_library("libtinykeccak.a", &["src/tinykeccak.c"]); } From 68ba0162792dee1ec350ae2ede8dc254f941a18e Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 04:25:03 +0100 Subject: [PATCH 313/753] improved blockchain generator --- ethcore/src/blockchain/blockchain.rs | 66 ++++---- ethcore/src/blockchain/generator/block.rs | 64 ++++++++ ethcore/src/blockchain/generator/bloom.rs | 35 ++++ ethcore/src/blockchain/generator/complete.rs | 53 ++++++ ethcore/src/blockchain/generator/fork.rs | 42 +++++ .../generators.rs => generator/generator.rs} | 154 +++++++----------- .../blockchain/{helpers => generator}/mod.rs | 9 +- ethcore/src/blockchain/mod.rs | 2 +- 8 files changed, 294 insertions(+), 131 deletions(-) create mode 100644 ethcore/src/blockchain/generator/block.rs create mode 100644 ethcore/src/blockchain/generator/bloom.rs create mode 100644 ethcore/src/blockchain/generator/complete.rs create mode 100644 ethcore/src/blockchain/generator/fork.rs rename ethcore/src/blockchain/{helpers/generators.rs => generator/generator.rs} (51%) rename ethcore/src/blockchain/{helpers => generator}/mod.rs (81%) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 53dcfb62c..10e844192 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -770,14 +770,15 @@ mod tests { use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; use tests::helpers::*; use devtools::*; - use blockchain::helpers::generators::{ChainGenerator, ChainIterator}; + use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer}; use views::BlockView; #[test] fn basic_blockchain_insert() { let mut canon_chain = ChainGenerator::default(); - let genesis = canon_chain.next().unwrap().rlp(); - let first = canon_chain.next().unwrap().rlp(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let first = canon_chain.generate(&mut finalizer).unwrap(); let genesis_hash = BlockView::new(&genesis).header_view().sha3(); let first_hash = BlockView::new(&first).header_view().sha3(); @@ -806,14 +807,12 @@ mod tests { #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { let mut canon_chain = ChainGenerator::default(); - let genesis = canon_chain.next().unwrap().rlp(); - let blocks = canon_chain.clone().take(3).map(|block| block.rlp()).collect::>(); - let fork = canon_chain.skip(2).fork(1).take(1).next().unwrap().rlp(); - - let b1 = blocks[0].clone(); - let b2 = blocks[1].clone(); - let b3a = blocks[2].clone(); - let b3b = fork; + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let b1 = canon_chain.generate(&mut finalizer).unwrap(); + let b2 = canon_chain.generate(&mut finalizer).unwrap(); + let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b3a = canon_chain.generate(&mut finalizer).unwrap(); let genesis_hash = BlockView::new(&genesis).header_view().sha3(); let b1_hash= BlockView::new(&b1).header_view().sha3(); @@ -897,22 +896,24 @@ mod tests { #[test] fn test_reopen_blockchain_db() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); - let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); - let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap(); - let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap(); + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let first = canon_chain.generate(&mut finalizer).unwrap(); + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + let first_hash = BlockView::new(&first).header_view().sha3(); let temp = RandomTempPath::new(); { let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); assert_eq!(bc.best_block_hash(), genesis_hash); - bc.insert_block(&b1, vec![]); - assert_eq!(bc.best_block_hash(), b1_hash); + bc.insert_block(&first, vec![]); + assert_eq!(bc.best_block_hash(), first_hash); } { let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); - assert_eq!(bc.best_block_hash(), b1_hash); + assert_eq!(bc.best_block_hash(), first_hash); } } @@ -976,29 +977,24 @@ mod tests { #[test] fn test_bloom_filter_simple() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); - - // block b1 (child of genesis) - let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000200000000000000000000000000000000000000000020000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080004000000000000000000000020008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); - - // block b2 (child of b1) - let b2 = "f902ccf901f9a04ef46c05763fffc5f7e59f92a7ef438ffccbb578e6e5d0f04e3df8a7fa6c02f6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - - // prepare for fork (b1a, child of genesis) - let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - - // fork (b2a, child of b1a, with higher total difficulty) - let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - - // fork back :) - let b3 = "f902ccf901f9a0e6cd7250e4c32b33c906aca30280911c560ac67bd0a05fbeb874f99ac7e7e47aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004003832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - + // TODO: From here let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap(); let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); let bloom_ba = H2048::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let mut fork = canon_chain.fork(1); + let mut fork_finalizer = finalizer.fork(); + let b1 = fork.with_bloom(bloom_b1.clone()).generate(&mut fork_finalizer).unwrap(); + let b2 = fork.with_bloom(bloom_b2.clone()).generate(&mut fork_finalizer).unwrap(); + let b3 = fork.with_bloom(bloom_ba.clone()).generate(&mut fork_finalizer).unwrap(); + let b1a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap(); + let b2a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap(); + let temp = RandomTempPath::new(); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); diff --git a/ethcore/src/blockchain/generator/block.rs b/ethcore/src/blockchain/generator/block.rs new file mode 100644 index 000000000..0a3dad399 --- /dev/null +++ b/ethcore/src/blockchain/generator/block.rs @@ -0,0 +1,64 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::rlp::*; +use util::{H256, H2048}; +use util::U256; +use util::bytes::Bytes; +use header::Header; +use transaction::SignedTransaction; + +use super::fork::Forkable; +use super::bloom::WithBloom; +use super::complete::CompleteBlock; + +/// Helper structure, used for encoding blocks. +#[derive(Default)] +pub struct Block { + pub header: Header, + pub transactions: Vec, + pub uncles: Vec
+} + +impl Encodable for Block { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(3); + s.append(&self.header); + s.append(&self.transactions); + s.append(&self.uncles); + } +} + +impl Forkable for Block { + fn fork(mut self, fork_number: usize) -> Self where Self: Sized { + self.header.difficulty = self.header.difficulty - U256::from(fork_number); + self + } +} + +impl WithBloom for Block { + fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized { + self.header.log_bloom = bloom; + self + } +} + +impl CompleteBlock for Block { + fn complete(mut self, parent_hash: H256) -> Bytes { + self.header.parent_hash = parent_hash; + encode(&self).to_vec() + } +} diff --git a/ethcore/src/blockchain/generator/bloom.rs b/ethcore/src/blockchain/generator/bloom.rs new file mode 100644 index 000000000..f61c9d1ff --- /dev/null +++ b/ethcore/src/blockchain/generator/bloom.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::hash::H2048; + +pub trait WithBloom { + fn with_bloom(self, bloom: H2048) -> Self where Self: Sized; +} + +pub struct Bloom<'a, I> where I: 'a { + pub iter: &'a mut I, + pub bloom: H2048, +} + +impl<'a, I> Iterator for Bloom<'a, I> where I: Iterator, ::Item: WithBloom { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| item.with_bloom(self.bloom.clone())) + } +} diff --git a/ethcore/src/blockchain/generator/complete.rs b/ethcore/src/blockchain/generator/complete.rs new file mode 100644 index 000000000..39bd587a0 --- /dev/null +++ b/ethcore/src/blockchain/generator/complete.rs @@ -0,0 +1,53 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::hash::H256; +use util::bytes::Bytes; +use util::sha3::Hashable; +use views::BlockView; + +#[derive(Default, Clone)] +pub struct BlockFinalizer { + parent_hash: H256 +} + +impl BlockFinalizer { + pub fn fork(&self) -> Self { + self.clone() + } +} + +pub trait CompleteBlock { + fn complete(self, parent_hash: H256) -> Bytes; +} + +pub struct Complete<'a, I> where I: 'a { + pub iter: &'a mut I, + pub finalizer: &'a mut BlockFinalizer, +} + +impl<'a, I> Iterator for Complete<'a, I> where I: Iterator, ::Item: CompleteBlock { + type Item = Bytes; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| { + let rlp = item.complete(self.finalizer.parent_hash.clone()); + self.finalizer.parent_hash = BlockView::new(&rlp).header_view().sha3(); + rlp + }) + } +} diff --git a/ethcore/src/blockchain/generator/fork.rs b/ethcore/src/blockchain/generator/fork.rs new file mode 100644 index 000000000..f3a4eb267 --- /dev/null +++ b/ethcore/src/blockchain/generator/fork.rs @@ -0,0 +1,42 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +pub trait Forkable { + fn fork(self, fork_number: usize) -> Self where Self: Sized; +} + +pub struct Fork { + pub iter: I, + pub fork_number: usize, +} + +impl Clone for Fork where I: Iterator + Clone { + fn clone(&self) -> Self { + Fork { + iter: self.iter.clone(), + fork_number: self.fork_number + } + } +} + +impl Iterator for Fork where I: Iterator, ::Item: Forkable { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| item.fork(self.fork_number)) + } +} diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/generator/generator.rs similarity index 51% rename from ethcore/src/blockchain/helpers/generators.rs rename to ethcore/src/blockchain/generator/generator.rs index a20b0cf79..d73b81733 100644 --- a/ethcore/src/blockchain/helpers/generators.rs +++ b/ethcore/src/blockchain/generator/generator.rs @@ -14,108 +14,52 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::rlp::*; -use util::hash::{H256, H2048}; -use util::uint::{U256}; +use util::hash::H2048; +use util::uint::U256; use util::bytes::Bytes; -use header::{BlockNumber, Header}; -use transaction::SignedTransaction; - -pub trait Forkable { - fn fork(self, fork_number: usize) -> Self where Self: Sized; -} - -pub struct Fork { - iter: I, - fork_number: usize, -} - -impl Iterator for Fork where I: Iterator, ::Item: Forkable { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|item| item.fork(self.fork_number)) - } -} - -pub trait WithBloom { - fn with_bloom(self, bloom: H2048) -> Self where Self: Sized; -} - -pub struct Bloom { - iter: I, - bloom: H2048, -} - -impl Iterator for Bloom where I: Iterator, ::Item: WithBloom { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|item| item.with_bloom(self.bloom.clone())) - } -} +use header::BlockNumber; +use super::fork::Fork; +use super::bloom::Bloom; +use super::complete::{BlockFinalizer, CompleteBlock, Complete}; +use super::block::Block; /// Chain iterator interface. -pub trait ChainIterator: Iterator { +pub trait ChainIterator: Iterator + Sized { /// Should be called to create a fork of current iterator. /// Blocks generated by fork will have lower difficulty than current chain. - fn fork(&mut self, fork_number: usize) -> Fork where Self: Sized; + fn fork(&self, fork_number: usize) -> Fork where Self: Clone; /// Should be called to make every consecutive block have given bloom. - fn with_bloom(&mut self, bloom: H2048) -> Bloom where Self: Sized; + fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self>; + /// Should be called to complete block. Without complete block may have incorrect hash. + fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>; + /// Completes and generates block. + fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where Self::Item: CompleteBlock; } -impl ChainIterator for I where I: Iterator + Sized + Clone { - fn fork(&mut self, fork_number: usize) -> Fork { +impl ChainIterator for I where I: Iterator + Sized { + fn fork(&self, fork_number: usize) -> Fork where I: Clone { Fork { iter: self.clone(), fork_number: fork_number } } - fn with_bloom(&mut self, bloom: H2048) -> Bloom { + fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self> { Bloom { - iter: self.clone(), + iter: self, bloom: bloom } } -} -/// Helper structure, used for encoding blocks. -#[derive(Default)] -pub struct Block { - header: Header, - transactions: Vec, - uncles: Vec
-} - -impl Block { - pub fn rlp(&self) -> Bytes { - encode(self).to_vec() + fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self> { + Complete { + iter: self, + finalizer: finalizer + } } -} -impl Encodable for Block { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.header); - s.append(&self.transactions); - s.append(&self.uncles); - } -} - -impl Forkable for Block { - fn fork(mut self, fork_number: usize) -> Self where Self: Sized { - self.header.difficulty = self.header.difficulty - U256::from(fork_number); - self - } -} - -impl WithBloom for Block { - fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized { - self.header.log_bloom = bloom; - self + fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where ::Item: CompleteBlock { + self.complete(finalizer).next() } } @@ -124,8 +68,6 @@ impl WithBloom for Block { pub struct ChainGenerator { /// Next block number. number: BlockNumber, - /// Next block parent hash. - parent_hash: H256, /// Next block difficulty. difficulty: U256, } @@ -133,7 +75,6 @@ pub struct ChainGenerator { impl ChainGenerator { fn prepare_block(&self) -> Block { let mut block = Block::default(); - block.header.parent_hash = self.parent_hash.clone(); block.header.number = self.number; block.header.difficulty = self.difficulty; block @@ -144,7 +85,6 @@ impl Default for ChainGenerator { fn default() -> Self { ChainGenerator { number: 0, - parent_hash: H256::default(), difficulty: U256::from(1000), } } @@ -156,30 +96,28 @@ impl Iterator for ChainGenerator { fn next(&mut self) -> Option { let block = self.prepare_block(); self.number += 1; - self.parent_hash = block.header.hash(); Some(block) } } - -#[cfg(test)] mod tests { - use util::hash::H256; + use util::hash::{H256, H2048}; use util::sha3::Hashable; use views::BlockView; - use super::{ChainIterator, ChainGenerator}; + use blockchain::generator::{ChainIterator, ChainGenerator, BlockFinalizer}; #[test] fn canon_chain_generator() { let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); - let genesis_rlp = canon_chain.next().unwrap().rlp(); + let genesis_rlp = canon_chain.generate(&mut finalizer).unwrap(); let genesis = BlockView::new(&genesis_rlp); assert_eq!(genesis.header_view().parent_hash(), H256::default()); assert_eq!(genesis.header_view().number(), 0); - let b1_rlp = canon_chain.next().unwrap().rlp(); + let b1_rlp = canon_chain.generate(&mut finalizer).unwrap(); let b1 = BlockView::new(&b1_rlp); assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3()); @@ -187,17 +125,45 @@ mod tests { let mut fork_chain = canon_chain.fork(1); - let b2_rlp_fork = fork_chain.next().unwrap().rlp(); + let b2_rlp_fork = fork_chain.generate(&mut finalizer.fork()).unwrap(); let b2_fork = BlockView::new(&b2_rlp_fork); assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3()); assert_eq!(b2_fork.header_view().number(), 2); - let b2_rlp = canon_chain.next().unwrap().rlp(); + let b2_rlp = canon_chain.generate(&mut finalizer).unwrap(); let b2 = BlockView::new(&b2_rlp); assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3()); assert_eq!(b2.header_view().number(), 2); assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty()); } + + #[test] + fn with_bloom_generator() { + let bloom = H2048([0x1; 256]); + let mut gen = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + + let block0_rlp = gen.with_bloom(bloom).generate(&mut finalizer).unwrap(); + let block1_rlp = gen.generate(&mut finalizer).unwrap(); + let block0 = BlockView::new(&block0_rlp); + let block1 = BlockView::new(&block1_rlp); + + assert_eq!(block0.header_view().number(), 0); + assert_eq!(block0.header_view().parent_hash(), H256::default()); + + assert_eq!(block1.header_view().number(), 1); + assert_eq!(block1.header_view().parent_hash(), block0.header_view().sha3()); + + } + + #[test] + fn generate_1000_blocks() { + let generator = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let blocks: Vec<_> = generator.take(1000).complete(&mut finalizer).collect(); + assert_eq!(blocks.len(), 1000); + } } + diff --git a/ethcore/src/blockchain/helpers/mod.rs b/ethcore/src/blockchain/generator/mod.rs similarity index 81% rename from ethcore/src/blockchain/helpers/mod.rs rename to ethcore/src/blockchain/generator/mod.rs index 233f8f1f8..88fdec0e4 100644 --- a/ethcore/src/blockchain/helpers/mod.rs +++ b/ethcore/src/blockchain/generator/mod.rs @@ -14,4 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -pub mod generators; +mod bloom; +mod block; +mod complete; +mod fork; +pub mod generator; + +pub use self::complete::BlockFinalizer; +pub use self::generator::{ChainIterator, ChainGenerator}; diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 60a1aeb33..b0679b563 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -24,7 +24,7 @@ mod cache; mod tree_route; mod update; #[cfg(test)] -mod helpers; +mod generator; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize; From 010659cf12b0accaa678232176d60f338f15f1a9 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 04:54:47 +0100 Subject: [PATCH 314/753] added missing , in comment --- ethcore/src/blockchain/generator/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/generator/generator.rs b/ethcore/src/blockchain/generator/generator.rs index d73b81733..16f2330c2 100644 --- a/ethcore/src/blockchain/generator/generator.rs +++ b/ethcore/src/blockchain/generator/generator.rs @@ -30,7 +30,7 @@ pub trait ChainIterator: Iterator + Sized { fn fork(&self, fork_number: usize) -> Fork where Self: Clone; /// Should be called to make every consecutive block have given bloom. fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self>; - /// Should be called to complete block. Without complete block may have incorrect hash. + /// Should be called to complete block. Without complete, block may have incorrect hash. fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>; /// Completes and generates block. fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where Self::Item: CompleteBlock; From 5f97d519673d2ad05d4739a409728ac10f271393 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 05:46:38 +0100 Subject: [PATCH 315/753] renamed poll_indexed to poll_manager --- rpc/src/v1/helpers/mod.rs | 4 ++-- .../{poll_indexer.rs => poll_manager.rs} | 22 +++++++++---------- rpc/src/v1/impls/eth.rs | 8 +++---- 3 files changed, 17 insertions(+), 17 deletions(-) rename rpc/src/v1/helpers/{poll_indexer.rs => poll_manager.rs} (88%) diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index d212d74ab..b1a5c05ba 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -mod poll_indexer; +mod poll_manager; mod poll_filter; -pub use self::poll_indexer::PollIndexer; +pub use self::poll_manager::PollManager; pub use self::poll_filter::PollFilter; diff --git a/rpc/src/v1/helpers/poll_indexer.rs b/rpc/src/v1/helpers/poll_manager.rs similarity index 88% rename from rpc/src/v1/helpers/poll_indexer.rs rename to rpc/src/v1/helpers/poll_manager.rs index 11cb30935..1e7addb25 100644 --- a/rpc/src/v1/helpers/poll_indexer.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -39,30 +39,30 @@ impl Clone for PollInfo where F: Clone { } /// Indexes all poll requests. -/// +/// /// Lazily garbage collects unused polls info. -pub struct PollIndexer where T: Timer { +pub struct PollManager where T: Timer { polls: TransientHashMap, T>, next_available_id: PollId } -impl PollIndexer { +impl PollManager { /// Creates new instance of indexer. pub fn new() -> Self { - PollIndexer::new_with_timer(Default::default()) + PollManager::new_with_timer(Default::default()) } } -impl PollIndexer where T: Timer { +impl PollManager where T: Timer { pub fn new_with_timer(timer: T) -> Self { - PollIndexer { + PollManager { polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), next_available_id: 0 } } - /// Returns id which can be used for new poll. - /// + /// Returns id which can be used for new poll. + /// /// Stores information when last poll happend. pub fn create_poll(&mut self, filter: F, block: BlockNumber) -> PollId { self.polls.prune(); @@ -84,7 +84,7 @@ impl PollIndexer where T: Timer { } /// Returns number of block when last poll happend. - pub fn get_poll(&mut self, id: &PollId) -> Option<&PollInfo> { + pub fn get_poll_info(&mut self, id: &PollId) -> Option<&PollInfo> { self.polls.prune(); self.polls.get(id) } @@ -99,7 +99,7 @@ impl PollIndexer where T: Timer { mod tests { use std::cell::RefCell; use transient_hashmap::Timer; - use v1::helpers::PollIndexer; + use v1::helpers::PollManager; struct TestTimer<'a> { time: &'a RefCell @@ -118,7 +118,7 @@ mod tests { time: &time }; - let mut indexer = PollIndexer::new_with_timer(timer); + let mut indexer = PollManager::new_with_timer(timer); assert_eq!(indexer.create_poll(false, 20), 0); assert_eq!(indexer.create_poll(true, 20), 1); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 32c143a84..880c45041 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -25,7 +25,7 @@ use ethcore::views::*; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; -use v1::helpers::{PollFilter, PollIndexer}; +use v1::helpers::{PollFilter, PollManager}; /// Eth rpc implementation. pub struct EthClient { @@ -214,7 +214,7 @@ impl Eth for EthClient { /// Eth filter rpc implementation. pub struct EthFilterClient { client: Weak, - polls: Mutex>, + polls: Mutex>, } impl EthFilterClient { @@ -222,7 +222,7 @@ impl EthFilterClient { pub fn new(client: &Arc) -> Self { EthFilterClient { client: Arc::downgrade(client), - polls: Mutex::new(PollIndexer::new()) + polls: Mutex::new(PollManager::new()) } } } @@ -263,7 +263,7 @@ impl EthFilter for EthFilterClient { let client = take_weak!(self.client); from_params::<(Index,)>(params) .and_then(|(index,)| { - let info = self.polls.lock().unwrap().get_poll(&index.value()).cloned(); + let info = self.polls.lock().unwrap().get_poll_info(&index.value()).cloned(); match info { None => Ok(Value::Array(vec![] as Vec)), Some(info) => match info.filter { From 05897ddbb0fd97e69209ef44b72886a5979a7e4c Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 05:50:28 +0100 Subject: [PATCH 316/753] fixed pending transaction mock implementation --- rpc/src/v1/impls/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 880c45041..f885441c5 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -280,7 +280,7 @@ impl EthFilter for EthFilterClient { }, PollFilter::PendingTransaction => { // TODO: fix implementation - to_value(&client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) + to_value(&vec![H256::default()]) }, PollFilter::Logs(mut filter) => { filter.from_block = BlockId::Number(info.block_number); From 32074cc420edf2f450e29c89a7ef64a58d2c6d6a Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 05:55:42 +0100 Subject: [PATCH 317/753] fixed compilation issue caused by incorrect merge --- ethcore/src/blockchain/generator/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/generator/generator.rs b/ethcore/src/blockchain/generator/generator.rs index 16f2330c2..51e6294fc 100644 --- a/ethcore/src/blockchain/generator/generator.rs +++ b/ethcore/src/blockchain/generator/generator.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::hash::H2048; -use util::uint::U256; +use util::numbers::U256; use util::bytes::Bytes; use header::BlockNumber; use super::fork::Fork; From 67a1f2065e2611c73e64bbf74c0812b224b64fd7 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 06:00:00 +0100 Subject: [PATCH 318/753] fixed broken master --- ethcore/src/blockchain/helpers/generators.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/helpers/generators.rs index a20b0cf79..2fd517e50 100644 --- a/ethcore/src/blockchain/helpers/generators.rs +++ b/ethcore/src/blockchain/helpers/generators.rs @@ -16,7 +16,7 @@ use util::rlp::*; use util::hash::{H256, H2048}; -use util::uint::{U256}; +use util::numbers::{U256}; use util::bytes::Bytes; use header::{BlockNumber, Header}; use transaction::SignedTransaction; From feff1f9e6e8837d1783ff307caa195af9ab63554 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 06:09:27 +0100 Subject: [PATCH 319/753] chainfilter shouldnt exclude to_block from results --- ethcore/src/chainfilter/chainfilter.rs | 24 ++++++++++++------------ ethcore/src/chainfilter/tests.rs | 16 ++++++++-------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs index fb6df877a..387d750fd 100644 --- a/ethcore/src/chainfilter/chainfilter.rs +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Multilevel blockchain bloom filter. -//! +//! //! ```not_run //! extern crate ethcore_util as util; //! extern crate ethcore; @@ -23,33 +23,33 @@ //! use util::sha3::*; //! use util::hash::*; //! use ethcore::chainfilter::*; -//! +//! //! fn main() { //! let (index_size, bloom_levels) = (16, 3); //! let mut cache = MemoryCache::new(); -//! +//! //! let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(); -//! +//! //! // borrow cache for reading inside the scope //! let modified_blooms = { -//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); +//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); //! let block_number = 39; //! let mut bloom = H2048::new(); //! bloom.shift_bloomed(&address.sha3()); //! filter.add_bloom(&bloom, block_number) //! }; -//! +//! //! // number of updated blooms is equal number of levels //! assert_eq!(modified_blooms.len(), bloom_levels as usize); //! //! // lets inserts modified blooms into the cache //! cache.insert_blooms(modified_blooms); -//! +//! //! // borrow cache for another reading operations //! { -//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); +//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); //! let blocks = filter.blocks_with_address(&address, 10, 40); -//! assert_eq!(blocks.len(), 1); +//! assert_eq!(blocks.len(), 1); //! assert_eq!(blocks[0], 39); //! } //! } @@ -71,7 +71,7 @@ pub struct ChainFilter<'a, D> impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource { /// Creates new filter instance. - /// + /// /// Borrows `FilterDataSource` for reading. pub fn new(data_source: &'a D, index_size: usize, levels: u8) -> Self { ChainFilter { @@ -88,7 +88,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource None => return None, Some(level_bloom) => match level { // if we are on the lowest level - 0 => return match offset < to_block { + 0 => return match offset <= to_block { // take the value if its smaller than to_block true if level_bloom.contains(bloom) => Some(vec![offset]), // return None if it is is equal to to_block @@ -153,7 +153,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource for i in 0..blooms.len() { let index = self.indexer.bloom_index(block_number + i, level); - let new_bloom = { + let new_bloom = { // use new blooms before db blooms where necessary let bloom_at = | index | { result.get(&index).cloned().or_else(|| self.data_source.bloom_at_index(&index)) }; diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs index 2baa93e55..08af44720 100644 --- a/ethcore/src/chainfilter/tests.rs +++ b/ethcore/src/chainfilter/tests.rs @@ -22,7 +22,7 @@ use util::sha3::*; use chainfilter::{BloomIndex, FilterDataSource, ChainFilter}; /// In memory cache for blooms. -/// +/// /// Stores all blooms in HashMap, which indexes them by `BloomIndex`. pub struct MemoryCache { blooms: HashMap, @@ -35,7 +35,7 @@ impl MemoryCache { } /// inserts all blooms into cache - /// + /// /// if bloom at given index already exists, overwrites it pub fn insert_blooms(&mut self, blooms: HashMap) { self.blooms.extend(blooms); @@ -81,13 +81,13 @@ fn test_topic_basic_search() { { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 23); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 22); assert_eq!(blocks.len(), 0); } { let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 23, 24); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 23, 23); assert_eq!(blocks.len(), 1); assert_eq!(blocks[0], 23); } @@ -144,7 +144,7 @@ fn test_reset_chain_head_simple() { cache.insert_blooms(modified_blooms_3); - + let reset_modified_blooms = { let filter = ChainFilter::new(&cache, index_size, bloom_levels); filter.reset_chain_head(&[to_bloom(&topic_4), to_bloom(&topic_5)], 15, 17) @@ -183,7 +183,7 @@ fn for_each_bloom(bytes: &[u8], mut f: F) where F: FnMut(usize, &H2048) { } fn for_each_log(bytes: &[u8], mut f: F) where F: FnMut(usize, &Address, &[H256]) { - let mut reader = BufReader::new(bytes); + let mut reader = BufReader::new(bytes); let mut line = String::new(); while reader.read_line(&mut line).unwrap() > 0 { { @@ -235,11 +235,11 @@ fn test_chainfilter_real_data_short_searches() { for_each_log(include_bytes!("logs.txt"), | block_number, address, topics | { println!("block_number: {:?}", block_number); let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_bloom(&to_bloom(address), block_number, block_number + 1); + let blocks = filter.blocks_with_bloom(&to_bloom(address), block_number, block_number); assert_eq!(blocks.len(), 1); for (i, topic) in topics.iter().enumerate() { println!("topic: {:?}", i); - let blocks = filter.blocks_with_bloom(&to_bloom(topic), block_number, block_number + 1); + let blocks = filter.blocks_with_bloom(&to_bloom(topic), block_number, block_number); assert_eq!(blocks.len(), 1); } }); From 34b812696b24427f3eb3bbb1c9f67119acf87230 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 2 Mar 2016 08:49:48 +0300 Subject: [PATCH 320/753] remove unused imports --- util/bigint/src/uint.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 4cc0dfc0e..5b67ba41d 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -40,20 +40,13 @@ use std::fmt; use std::cmp; use std::mem; -use std::ops; -use std::slice; -use std::result; -use std::option; use std::str::{FromStr}; use std::convert::From; use std::hash::{Hash, Hasher}; use std::ops::*; use std::cmp::*; -use std::collections::*; use serde; -use rustc_serialize::json::Json; -use rustc_serialize::base64::FromBase64; use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; From 5dfc3d28491e0e98b54e34a027031e6a54163832 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 2 Mar 2016 13:01:38 +0300 Subject: [PATCH 321/753] resolving path at runtime --- util/cov.sh | 2 +- util/src/keys/geth_import.rs | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/util/cov.sh b/util/cov.sh index 19aa3b892..121f9629d 100755 --- a/util/cov.sh +++ b/util/cov.sh @@ -5,5 +5,5 @@ fi cargo test --no-run || exit $? mkdir -p target/coverage -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1 --include-pattern src --verify target/coverage target/debug/ethcore_util* +./kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1 --include-pattern src --verify target/coverage target/debug/ethcore_util* xdg-open target/coverage/index.html diff --git a/util/src/keys/geth_import.rs b/util/src/keys/geth_import.rs index cdbd9b213..dbd9f0fe0 100644 --- a/util/src/keys/geth_import.rs +++ b/util/src/keys/geth_import.rs @@ -99,10 +99,20 @@ mod tests { use common::*; use keys::store::SecretStore; + fn test_path() -> &'static str { + match ::std::fs::metadata("res") { + Ok(_) => "res/geth_keystore", + Err(_) => "util/res/geth_keystore" + } + } + + fn test_path_param(param_val: &'static str) -> String { + test_path().to_owned() + param_val + } #[test] fn can_enumerate() { - let keys = enumerate_geth_keys(Path::new("res/geth_keystore")).unwrap(); + let keys = enumerate_geth_keys(Path::new(test_path())).unwrap(); assert_eq!(2, keys.len()); } @@ -110,7 +120,7 @@ mod tests { fn can_import() { let temp = ::devtools::RandomTempPath::create_dir(); let mut secret_store = SecretStore::new_in(temp.as_path()); - import_geth_key(&mut secret_store, Path::new("res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9")).unwrap(); + import_geth_key(&mut secret_store, Path::new(&test_path_param("/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9"))).unwrap(); let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); assert!(key.is_some()); } @@ -119,7 +129,7 @@ mod tests { fn can_import_directory() { let temp = ::devtools::RandomTempPath::create_dir(); let mut secret_store = SecretStore::new_in(temp.as_path()); - import_geth_keys(&mut secret_store, Path::new("res/geth_keystore")).unwrap(); + import_geth_keys(&mut secret_store, Path::new(test_path())).unwrap(); let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); assert!(key.is_some()); @@ -134,7 +144,7 @@ mod tests { let temp = ::devtools::RandomTempPath::create_dir(); { let mut secret_store = SecretStore::new_in(temp.as_path()); - import_geth_keys(&mut secret_store, Path::new("res/geth_keystore")).unwrap(); + import_geth_keys(&mut secret_store, Path::new(test_path())).unwrap(); } let key_directory = KeyDirectory::new(&temp.as_path()); @@ -156,7 +166,7 @@ mod tests { let temp = ::devtools::RandomTempPath::create_dir(); let mut secret_store = SecretStore::new_in(temp.as_path()); - import_geth_keys(&mut secret_store, Path::new("res/geth_keystore")).unwrap(); + import_geth_keys(&mut secret_store, Path::new(test_path())).unwrap(); let val = secret_store.get::(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap(), "123"); assert!(val.is_ok()); From 771fbcbd27bd900902f7705bd9d107f129e0ca2b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 2 Mar 2016 13:02:33 +0300 Subject: [PATCH 322/753] remove redundant modification --- util/cov.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/cov.sh b/util/cov.sh index 121f9629d..19aa3b892 100755 --- a/util/cov.sh +++ b/util/cov.sh @@ -5,5 +5,5 @@ fi cargo test --no-run || exit $? mkdir -p target/coverage -./kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1 --include-pattern src --verify target/coverage target/debug/ethcore_util* +kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1 --include-pattern src --verify target/coverage target/debug/ethcore_util* xdg-open target/coverage/index.html From 28c5f6f9c3acdab23a8b990cad133da6d9381bb6 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 12:32:30 +0100 Subject: [PATCH 323/753] fixed failing test --- rpc/src/v1/helpers/poll_manager.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index 1e7addb25..33b98af45 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -124,21 +124,21 @@ mod tests { *time.borrow_mut() = 10; indexer.update_poll(&0, 21); - assert_eq!(indexer.get_poll(&0).unwrap().filter, false); - assert_eq!(indexer.get_poll(&0).unwrap().block_number, 21); + assert_eq!(indexer.get_poll_info(&0).unwrap().filter, false); + assert_eq!(indexer.get_poll_info(&0).unwrap().block_number, 21); *time.borrow_mut() = 30; indexer.update_poll(&1, 23); - assert_eq!(indexer.get_poll(&1).unwrap().filter, true); - assert_eq!(indexer.get_poll(&1).unwrap().block_number, 23); + assert_eq!(indexer.get_poll_info(&1).unwrap().filter, true); + assert_eq!(indexer.get_poll_info(&1).unwrap().block_number, 23); *time.borrow_mut() = 75; indexer.update_poll(&0, 30); - assert!(indexer.get_poll(&0).is_none()); - assert_eq!(indexer.get_poll(&1).unwrap().filter, true); - assert_eq!(indexer.get_poll(&1).unwrap().block_number, 23); + assert!(indexer.get_poll_info(&0).is_none()); + assert_eq!(indexer.get_poll_info(&1).unwrap().filter, true); + assert_eq!(indexer.get_poll_info(&1).unwrap().block_number, 23); indexer.remove_poll(&1); - assert!(indexer.get_poll(&1).is_none()); + assert!(indexer.get_poll_info(&1).is_none()); } } From bdf3b197ad8400dc1b9037b49cd695b971ee578b Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 12:42:08 +0100 Subject: [PATCH 324/753] limit serde codegen only to rpc types submodule --- rpc/build.rs | 4 ++-- rpc/src/lib.rs | 33 +++++++++++++++++++++++++++++---- rpc/src/lib.rs.in | 30 ------------------------------ rpc/src/v1/impls/web3.rs | 4 +--- rpc/src/v1/types/mod.rs | 22 ++++------------------ rpc/src/v1/types/mod.rs.in | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 57 deletions(-) delete mode 100644 rpc/src/lib.rs.in create mode 100644 rpc/src/v1/types/mod.rs.in diff --git a/rpc/build.rs b/rpc/build.rs index fe1a55694..b5adeaba1 100644 --- a/rpc/build.rs +++ b/rpc/build.rs @@ -9,8 +9,8 @@ mod inner { pub fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); - let src = Path::new("src/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); + let src = Path::new("src/v1/types/mod.rs.in"); + let dst = Path::new(&out_dir).join("mod.rs"); let mut registry = syntex::Registry::new(); diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 8dd58d0b8..4559f766c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -28,8 +28,33 @@ extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; -#[cfg(feature = "serde_macros")] -include!("lib.rs.in"); +use self::jsonrpc_core::{IoHandler, IoDelegate}; -#[cfg(not(feature = "serde_macros"))] -include!(concat!(env!("OUT_DIR"), "/lib.rs")); +pub mod v1; + +/// Http server. +pub struct HttpServer { + handler: IoHandler, + threads: usize +} + +impl HttpServer { + /// Construct new http server object with given number of threads. + pub fn new(threads: usize) -> HttpServer { + HttpServer { + handler: IoHandler::new(), + threads: threads + } + } + + /// Add io delegate. + pub fn add_delegate(&mut self, delegate: IoDelegate) where D: Send + Sync + 'static { + self.handler.add_delegate(delegate); + } + + /// Start server asynchronously in new thread + pub fn start_async(self, addr: &str, cors_domain: &str) { + let server = jsonrpc_http_server::Server::new(self.handler, self.threads); + server.start_async(addr, jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain.to_owned())) + } +} diff --git a/rpc/src/lib.rs.in b/rpc/src/lib.rs.in deleted file mode 100644 index e17f2b3bb..000000000 --- a/rpc/src/lib.rs.in +++ /dev/null @@ -1,30 +0,0 @@ -use self::jsonrpc_core::{IoHandler, IoDelegate}; - -pub mod v1; - -/// Http server. -pub struct HttpServer { - handler: IoHandler, - threads: usize -} - -impl HttpServer { - /// Construct new http server object with given number of threads. - pub fn new(threads: usize) -> HttpServer { - HttpServer { - handler: IoHandler::new(), - threads: threads - } - } - - /// Add io delegate. - pub fn add_delegate(&mut self, delegate: IoDelegate) where D: Send + Sync + 'static { - self.handler.add_delegate(delegate); - } - - /// Start server asynchronously in new thread - pub fn start_async(self, addr: &str, cors_domain: &str) { - let server = jsonrpc_http_server::Server::new(self.handler, self.threads); - server.start_async(addr, jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain.to_owned())) - } -} diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index 0a237d56b..1cfe35631 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -30,9 +30,7 @@ impl Web3Client { impl Web3 for Web3Client { fn client_version(&self, params: Params) -> Result { match params { - Params::None => { - Ok(Value::String(version())), - } + Params::None => Ok(Value::String(version())), _ => Err(Error::invalid_params()) } } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 34c1f1cff..adf9be071 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -14,22 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -mod block; -mod block_number; -mod bytes; -mod filter; -mod index; -mod log; -mod optionals; -mod sync; -mod transaction; +#[cfg(feature = "serde_macros")] +include!("mod.rs.in"); -pub use self::block::{Block, BlockTransactions}; -pub use self::block_number::BlockNumber; -pub use self::bytes::Bytes; -pub use self::filter::Filter; -pub use self::index::Index; -pub use self::log::Log; -pub use self::optionals::OptionalValue; -pub use self::sync::{SyncStatus, SyncInfo}; -pub use self::transaction::Transaction; +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/mod.rs")); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in new file mode 100644 index 000000000..34c1f1cff --- /dev/null +++ b/rpc/src/v1/types/mod.rs.in @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +mod block; +mod block_number; +mod bytes; +mod filter; +mod index; +mod log; +mod optionals; +mod sync; +mod transaction; + +pub use self::block::{Block, BlockTransactions}; +pub use self::block_number::BlockNumber; +pub use self::bytes::Bytes; +pub use self::filter::Filter; +pub use self::index::Index; +pub use self::log::Log; +pub use self::optionals::OptionalValue; +pub use self::sync::{SyncStatus, SyncInfo}; +pub use self::transaction::Transaction; From 3309959139cd8308367e83cf80d3639866beb268 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 12:57:34 +0100 Subject: [PATCH 325/753] Additional check to ancient enactments. --- ethcore/src/client.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index f2894decb..803f5c9db 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -257,6 +257,14 @@ impl Client { let engine = self.engine.deref().deref(); let header = &block.header; + // Check the block isn't so old we won't be able to enact it. + let best_block_number = self.chain.read().unwrap().best_block_number(); + debug!("Best: {}, importing: {}", best_block_number, header.number()); + if header.number() <= best_block_number - HISTORY { + warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number); + return Err(()); + } + // Verify Block Family let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); if let Err(e) = verify_family_result { From 041cfda80badaf98f4828121a28fabae7591abd1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 2 Mar 2016 13:21:33 +0100 Subject: [PATCH 326/753] Improved journaldb logging --- util/src/journaldb.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index cfcff6ea4..5e6ca47c2 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -121,6 +121,7 @@ impl JournalDB { // and the key is safe to delete. // record new commit's details. + debug!("commit: #{} ({}), end era: {:?}", now, id, end); let batch = DBTransaction::new(); let mut counters = self.counters.write().unwrap(); { @@ -167,15 +168,18 @@ impl JournalDB { &last })) { let rlp = Rlp::new(&rlp_data); - let inserts: Vec = rlp.val_at(1); + let mut inserts: Vec = rlp.val_at(1); JournalDB::decrease_counters(&inserts, &mut counters); // Collect keys to be removed. These are removed keys for canonical block, inserted for non-canonical if canon_id == rlp.val_at(0) { - to_remove.extend(rlp.at(2).iter().map(|r| r.as_val::())); + let mut canon_deletes: Vec = rlp.val_at(2); + trace!("Purging nodes deleted from canon: {:?}", canon_deletes); + to_remove.append(&mut canon_deletes); canon_inserts = inserts; } else { - to_remove.extend(inserts); + trace!("Purging nodes inserted in non-canon: {:?}", inserts); + to_remove.append(&mut inserts); } try!(batch.delete(&last)); index += 1; @@ -188,7 +192,7 @@ impl JournalDB { try!(batch.delete(&h)); deletes += 1; } - trace!("JournalDB: delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, deletes); + debug!("commit: Delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, deletes); } // Commit overlay insertions @@ -209,7 +213,7 @@ impl JournalDB { } try!(self.backing.write(batch)); - trace!("JournalDB::commit() deleted {} nodes", deletes); + debug!("commit: Deleted {} nodes", deletes); Ok(ret) } @@ -258,7 +262,7 @@ impl JournalDB { era -= 1; } } - trace!("Recovered {} counters", res.len()); + debug!("Recovered {} counters", res.len()); res } } From 47b47293323074f812a713477e435e18219c971f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 13:28:51 +0100 Subject: [PATCH 327/753] Fix check. --- ethcore/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 268d99229..bf6f4bd71 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -268,7 +268,7 @@ impl Client { // Check the block isn't so old we won't be able to enact it. let best_block_number = self.chain.read().unwrap().best_block_number(); debug!("Best: {}, importing: {}", best_block_number, header.number()); - if header.number() <= best_block_number - HISTORY { + if best_block_number >= HISTORY && header.number() <= best_block_number - HISTORY { warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number); return Err(()); } From 1ae573bf21cc183bbffe06e1c2c84bc8c17c7e85 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 13:40:11 +0100 Subject: [PATCH 328/753] Fix install-deps.sh. --- install-deps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-deps.sh b/install-deps.sh index 6cc7de002..7a5db1003 100755 --- a/install-deps.sh +++ b/install-deps.sh @@ -569,7 +569,7 @@ function run_installer() if [[ $isSudo == false ]]; then apt-get install -q -y sudo fi - curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes + curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes echo fi From 190468e1f85175b72f1f460dd5810e7ae4a62da6 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 14:03:43 +0100 Subject: [PATCH 329/753] fixed trailing , --- rpc/src/v1/helpers/poll_manager.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index 33b98af45..36a6352c2 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -57,7 +57,7 @@ impl PollManager where T: Timer { pub fn new_with_timer(timer: T) -> Self { PollManager { polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), - next_available_id: 0 + next_available_id: 0, } } @@ -70,7 +70,7 @@ impl PollManager where T: Timer { self.next_available_id += 1; self.polls.insert(id, PollInfo { filter: filter, - block_number: block + block_number: block, }); id } @@ -102,7 +102,7 @@ mod tests { use v1::helpers::PollManager; struct TestTimer<'a> { - time: &'a RefCell + time: &'a RefCell, } impl<'a> Timer for TestTimer<'a> { @@ -115,7 +115,7 @@ mod tests { fn test_poll_indexer() { let time = RefCell::new(0); let timer = TestTimer { - time: &time + time: &time, }; let mut indexer = PollManager::new_with_timer(timer); From b1a62575c9fe86ebe8299c8f6238892fedfeb6c0 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 2 Mar 2016 14:09:44 +0100 Subject: [PATCH 330/753] fixed PollFilter::PendingTransaction returning empty hash --- rpc/src/v1/impls/eth.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2baaf5225..2313d5114 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -323,8 +323,8 @@ impl EthFilter for EthFilterClient { to_value(&hashes) }, PollFilter::PendingTransaction => { - // TODO: fix implementation - to_value(&vec![H256::default()]) + // TODO: fix implementation once TransactionQueue is merged + to_value(&vec![] as &Vec) }, PollFilter::Logs(mut filter) => { filter.from_block = BlockId::Number(info.block_number); From 02aad03f9204acfb51ec65b52c2d35395ee76197 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 2 Mar 2016 17:06:53 +0300 Subject: [PATCH 331/753] helpers --- ethcore/src/tests/client.rs | 19 +++++++++++++ ethcore/src/tests/helpers.rs | 52 +++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 83df81fa2..e2671d63e 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -106,3 +106,22 @@ fn can_collect_garbage() { client.tick(); assert!(client.blockchain_cache_info().blocks < 100 * 1024); } + +#[test] +fn can_handle_long_fork() { + let client_result = generate_dummy_client(1200); + let client = client_result.reference(); + for _ in 0..10 { + client.import_verified_blocks(&IoChannel::disconnected()); + } + assert_eq!(1200, client.chain_info().best_block_number); + + push_blocks_to_client(client, 45, 1201, 800); + push_blocks_to_client(client, 49, 1201, 800); + push_blocks_to_client(client, 53, 1201, 600); + + for _ in 0..20 { + client.import_verified_blocks(&IoChannel::disconnected()); + } + assert_eq!(2000, client.chain_info().best_block_number); +} diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 44ad667b9..bb9a44614 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -156,10 +156,9 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult rolling_block_number = rolling_block_number + 1; rolling_timestamp = rolling_timestamp + 10; - if let Err(_) = client.import_block(create_test_block(&header)) { - panic!("error importing block which is valid by definition"); + if let Err(e) = client.import_block(create_test_block(&header)) { + panic!("error importing block which is valid by definition: {:?}", e); } - } client.flush_queue(); client.import_verified_blocks(&IoChannel::disconnected()); @@ -170,6 +169,34 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult } } +pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting_number: usize, block_number: usize) { + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + let state_root = test_engine.spec().genesis_header().state_root; + let mut rolling_hash = client.chain_info().best_block_hash; + let mut rolling_block_number = starting_number as u64; + let mut rolling_timestamp = timestamp_salt + starting_number as u64 * 10; + + for _ in 0..block_number { + let mut header = Header::new(); + + header.gas_limit = decode(test_engine.spec().engine_params.get("minGasLimit").unwrap()); + header.difficulty = decode(test_engine.spec().engine_params.get("minimumDifficulty").unwrap()); + header.timestamp = rolling_timestamp; + header.number = rolling_block_number; + header.parent_hash = rolling_hash; + header.state_root = state_root.clone(); + + rolling_hash = header.hash(); + rolling_block_number = rolling_block_number + 1; + rolling_timestamp = rolling_timestamp + 10; + + if let Err(e) = client.import_block(create_test_block(&header)) { + panic!("error importing block which is valid by definition: {:?}", e); + } + } +} + pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { let dir = RandomTempPath::new(); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); @@ -253,18 +280,29 @@ pub fn get_temp_state_in(path: &Path) -> State { pub fn get_good_dummy_block_seq(count: usize) -> Vec { let test_spec = get_test_spec(); let test_engine = test_spec.to_engine().unwrap(); - let mut parent = test_engine.spec().genesis_header().hash(); + get_good_dummy_block_fork_seq(1, count, &test_engine.spec().genesis_header().hash()) +} + +pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_hash: &H256) -> Vec { + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + let mut rolling_timestamp = start_number as u64 * 10; + let mut parent = *parent_hash; let mut r = Vec::new(); - for i in 1 .. count + 1 { + for i in start_number .. start_number + count + 1 { let mut block_header = Header::new(); block_header.gas_limit = decode(test_engine.spec().engine_params.get("minGasLimit").unwrap()); - block_header.difficulty = decode(test_engine.spec().engine_params.get("minimumDifficulty").unwrap()); - block_header.timestamp = i as u64; + block_header.difficulty = U256::from(i).mul(U256([0, 1, 0, 0])); + block_header.timestamp = rolling_timestamp; block_header.number = i as u64; block_header.parent_hash = parent; block_header.state_root = test_engine.spec().genesis_header().state_root; + parent = block_header.hash(); + rolling_timestamp = rolling_timestamp + 10; + r.push(create_test_block(&block_header)); + } r } From 3c7814c8ac6882e3c9fe8b54e10c7ee2e14e5518 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 15:43:48 +0100 Subject: [PATCH 332/753] Remove debug line. --- ethcore/src/client.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index bf6f4bd71..cc5e23869 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -267,7 +267,6 @@ impl Client { // Check the block isn't so old we won't be able to enact it. let best_block_number = self.chain.read().unwrap().best_block_number(); - debug!("Best: {}, importing: {}", best_block_number, header.number()); if best_block_number >= HISTORY && header.number() <= best_block_number - HISTORY { warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number); return Err(()); From c75737bcf0318a51f7bc19ab23d78e630481adf6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 17:04:44 +0100 Subject: [PATCH 333/753] Add ancestry iterator. --- ethcore/src/blockchain/blockchain.rs | 52 ++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 185bcaad3..6e5d92a45 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -227,6 +227,23 @@ impl BlockProvider for BlockChain { const COLLECTION_QUEUE_SIZE: usize = 8; +pub struct AncestryIter<'a> { + current: H256, + chain: &'a BlockChain, +} +impl<'a> Iterator for AncestryIter<'a> { + type Item = H256; + fn next(&mut self) -> Option { + if self.current.is_zero() { + Option::None + } else { + let n = self.chain.block_details(&self.current).unwrap().parent; + self.current = n; + Some(self.current.clone()) + } + } +} + impl BlockChain { /// Create new instance of blockchain from given Genesis pub fn new(config: BlockChainConfig, genesis: &[u8], path: &Path) -> BlockChain { @@ -473,9 +490,40 @@ impl BlockChain { self.extras_db.write(batch).unwrap(); } + pub fn ancestry_iter(&self, first: H256) -> AncestryIter { + AncestryIter { + current: first, + chain: &self, + } + } + /// Given a block's `parent`, find every block header which represents a valid uncle. - pub fn find_uncle_headers(&self, _parent: &H256) -> Vec
{ - // TODO + pub fn find_uncle_headers(&self, parent: &H256) -> Vec
{ + let uncle_generations = 6usize; +/* + { + // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. + clog(StateDetail) << "Checking " << m_previousBlock.hash() << ", parent=" << m_previousBlock.parentHash(); + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); + for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) + { + auto us = _bc.details(p).children; + assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! + for (auto const& u: us) + if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. + { + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); + ++unclesCount; + if (unclesCount == 2) + break; + } + } + } +*/ + let _excluded = self.ancestry_iter(parent.clone()).take(uncle_generations).collect::>(); + Vec::new() } From 671965d44fdf60547d85cd0689f62da46321ea4d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 17:31:42 +0100 Subject: [PATCH 334/753] Test for ancestry. --- ethcore/src/blockchain/blockchain.rs | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 6e5d92a45..d40a34b0c 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -231,15 +231,16 @@ pub struct AncestryIter<'a> { current: H256, chain: &'a BlockChain, } + impl<'a> Iterator for AncestryIter<'a> { type Item = H256; fn next(&mut self) -> Option { if self.current.is_zero() { Option::None } else { - let n = self.chain.block_details(&self.current).unwrap().parent; - self.current = n; - Some(self.current.clone()) + let mut n = self.chain.block_details(&self.current).unwrap().parent; + mem::swap(&mut self.current, &mut n); + Some(n) } } } @@ -857,6 +858,28 @@ mod tests { assert_eq!(bc.block_hash(2), None); } + #[test] + fn check_ancestry_iter() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + + let mut block_hashes = vec![genesis_hash.clone()]; + for _ in 0..10 { + let block = canon_chain.generate(&mut finalizer).unwrap(); + block_hashes.push(BlockView::new(&block).header_view().sha3()); + bc.insert_block(&block, vec![]); + } + + block_hashes.reverse(); + + assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).collect::>(), block_hashes) + } + #[test] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { From 42df98450c3c2edcf9c1898d20c23cb012928b32 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 18:05:47 +0100 Subject: [PATCH 335/753] Include uncles in exclused. --- ethcore/src/blockchain/blockchain.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index d40a34b0c..6779051e2 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -78,7 +78,7 @@ pub trait BlockProvider { } /// Get a list of uncles for a given block. - /// Returns None if block deos not exist. + /// Returns None if block does not exist. fn uncles(&self, hash: &H256) -> Option> { self.block(hash).map(|bytes| BlockView::new(&bytes).uncles()) } @@ -491,7 +491,7 @@ impl BlockChain { self.extras_db.write(batch).unwrap(); } - pub fn ancestry_iter(&self, first: H256) -> AncestryIter { + pub fn ancestry_iter(&self, first: H256) -> Option { AncestryIter { current: first, chain: &self, @@ -503,7 +503,8 @@ impl BlockChain { let uncle_generations = 6usize; /* { - // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. + // Find great-uncles (or second-cousins or whatever they are) - + // children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. clog(StateDetail) << "Checking " << m_previousBlock.hash() << ", parent=" << m_previousBlock.parentHash(); h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); auto p = m_previousBlock.parentHash(); @@ -523,7 +524,11 @@ impl BlockChain { } } */ - let _excluded = self.ancestry_iter(parent.clone()).take(uncle_generations).collect::>(); + let _excluded = self + .ancestry_iter(parent.clone()) + .take(uncle_generations) + .flat_map(|h| self.uncle_hashes(&h).iter().chain(&[h])) + .collect::>(); Vec::new() } From 877270c35fe68adb967a5d0714d5c3e15eaf91fc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 18:32:54 +0100 Subject: [PATCH 336/753] Fixes. --- ethcore/src/blockchain/blockchain.rs | 31 +++++++++++++++++----------- ethcore/src/client.rs | 4 ++-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 6779051e2..6b0939df5 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -491,15 +491,20 @@ impl BlockChain { self.extras_db.write(batch).unwrap(); } + /// Iterator that lists `first` and then all of `first`'s ancestors, by hash. pub fn ancestry_iter(&self, first: H256) -> Option { - AncestryIter { - current: first, - chain: &self, + if self.is_known(&first) { + Some(AncestryIter { + current: first, + chain: &self, + }) + } else { + None } } /// Given a block's `parent`, find every block header which represents a valid uncle. - pub fn find_uncle_headers(&self, parent: &H256) -> Vec
{ + pub fn find_uncle_headers(&self, parent: &H256) -> Option> { let uncle_generations = 6usize; /* { @@ -524,13 +529,15 @@ impl BlockChain { } } */ - let _excluded = self - .ancestry_iter(parent.clone()) - .take(uncle_generations) - .flat_map(|h| self.uncle_hashes(&h).iter().chain(&[h])) - .collect::>(); - - Vec::new() + if !self.is_known(parent) { return None; } + let mut _excluded = HashSet::new(); + for a in self.ancestry_iter(parent.clone()).unwrap().take(uncle_generations) { + for u in self.uncle_hashes(&a).unwrap().into_iter() { + _excluded.insert(u); + } + _excluded.insert(a); + } + None } /// Get inserted block info which is critical to preapre extras updates. @@ -882,7 +889,7 @@ mod tests { block_hashes.reverse(); - assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).collect::>(), block_hashes) + assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).unwrap().collect::>(), block_hashes) } #[test] diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index cc5e23869..105090580 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -200,7 +200,7 @@ pub struct Client { extra_data: RwLock, } -const HISTORY: u64 = 1000; +const HISTORY: u64 = 2000000; const CLIENT_DB_VER_STR: &'static str = "4.0"; impl Client { @@ -457,7 +457,7 @@ impl Client { self.extra_data() ); - self.chain.read().unwrap().find_uncle_headers(&h).into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); + self.chain.read().unwrap().find_uncle_headers(&h).unwrap().into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); // TODO: push transactions. From 039c0056bc0f58bfe33860c7a4aab7b9aff57bbc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 19:38:00 +0100 Subject: [PATCH 337/753] Uncle inclusion in block authoring. Still need tests. --- ethcore/src/blockchain/blockchain.rs | 46 +++++++++------------------- ethcore/src/client.rs | 2 +- ethcore/src/engine.rs | 2 ++ ethcore/src/verification.rs | 4 +-- 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 6b0939df5..4cf2d96c5 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -503,41 +503,23 @@ impl BlockChain { } } - /// Given a block's `parent`, find every block header which represents a valid uncle. - pub fn find_uncle_headers(&self, parent: &H256) -> Option> { - let uncle_generations = 6usize; -/* - { - // Find great-uncles (or second-cousins or whatever they are) - - // children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. - clog(StateDetail) << "Checking " << m_previousBlock.hash() << ", parent=" << m_previousBlock.parentHash(); - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); - auto p = m_previousBlock.parentHash(); - for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) - { - auto us = _bc.details(p).children; - assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! - for (auto const& u: us) - if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. - { - uncleBlockHeaders.push_back(_bc.info(u)); - unclesData.appendRaw(_bc.headerData(u)); - ++unclesCount; - if (unclesCount == 2) - break; - } - } - } -*/ + /// Given a block's `parent`, find every block header which represents a valid possible uncle. + pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { if !self.is_known(parent) { return None; } - let mut _excluded = HashSet::new(); + + let mut excluded = HashSet::new(); for a in self.ancestry_iter(parent.clone()).unwrap().take(uncle_generations) { - for u in self.uncle_hashes(&a).unwrap().into_iter() { - _excluded.insert(u); - } - _excluded.insert(a); + excluded.extend(self.uncle_hashes(&a).unwrap().into_iter()); + excluded.insert(a); } - None + + let mut ret = Vec::new(); + for a in self.ancestry_iter(parent.clone()).unwrap().skip(1).take(uncle_generations) { + ret.extend(self.block_details(&a).unwrap().children.iter() + .filter_map(|h| if excluded.contains(h) { None } else { self.block_header(h) }) + ); + } + Some(ret) } /// Get inserted block info which is critical to preapre extras updates. diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 105090580..4ddb40477 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -457,7 +457,7 @@ impl Client { self.extra_data() ); - self.chain.read().unwrap().find_uncle_headers(&h).unwrap().into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); + self.chain.read().unwrap().find_uncle_headers(&h, self.engine.deref().deref().maximum_uncle_age()).unwrap().into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); // TODO: push transactions. diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index d607ce2e2..83e1986fd 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -47,6 +47,8 @@ pub trait Engine : Sync + Send { fn maximum_extra_data_size(&self) -> usize { decode(&self.spec().engine_params.get("maximumExtraDataSize").unwrap()) } /// Maximum number of uncles a block is allowed to declare. fn maximum_uncle_count(&self) -> usize { 2 } + /// The number of generations back that uncles can be. + fn maximum_uncle_age(&self) -> usize { 6 } /// The nonce with which accounts begin. fn account_start_nonce(&self) -> U256 { decode(&self.spec().engine_params.get("accountStartNonce").unwrap()) } diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index f52e2e1e4..23b850f55 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -94,7 +94,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b excluded.insert(header.hash()); let mut hash = header.parent_hash.clone(); excluded.insert(hash.clone()); - for _ in 0..6 { + for _ in 0..engine.maximum_uncle_age() { match bc.block_details(&hash) { Some(details) => { excluded.insert(details.parent.clone()); @@ -121,7 +121,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b // (8 Invalid) let depth = if header.number > uncle.number { header.number - uncle.number } else { 0 }; - if depth > 6 { + if depth > engine.maximum_uncle_age() as u64 { return Err(From::from(BlockError::UncleTooOld(OutOfBounds { min: Some(header.number - depth), max: Some(header.number - 1), found: uncle.number }))); } else if depth < 1 { From fc9999fb059576cb040e3d0d8e2526f693412802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 2 Mar 2016 21:26:48 +0100 Subject: [PATCH 338/753] Changing uint to numbers --- sync/src/transaction_queue.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 341607afe..f2e15f955 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -21,7 +21,7 @@ use std::vec::Vec; use std::cmp::{Ordering}; use std::collections::{HashMap, BTreeSet}; -use util::uint::{Uint, U256}; +use util::numbers::{Uint, U256}; use util::hash::{Address}; use util::table::*; use ethcore::transaction::*; @@ -373,7 +373,7 @@ mod test { use self::rustc_serialize::hex::FromHex; use util::crypto::KeyPair; - use util::uint::{U256, Uint}; + use util::numbers::{U256, Uint}; use util::hash::{Address}; use ethcore::transaction::*; use super::*; From 6933bb971ba8947ead271ec8825452fc3fd7ae20 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 23:41:15 +0100 Subject: [PATCH 339/753] Test. --- ethcore/src/blockchain/blockchain.rs | 38 ++++++++++++++++++++++++++++ ethcore/src/header.rs | 21 ++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 4cf2d96c5..394c16e85 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -874,6 +874,44 @@ mod tests { assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).unwrap().collect::>(), block_hashes) } + #[test] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + fn test_find_uncles() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let b1b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b1a = canon_chain.generate(&mut finalizer).unwrap(); + let b2b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b2a = canon_chain.generate(&mut finalizer).unwrap(); + let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b3a = canon_chain.generate(&mut finalizer).unwrap(); + let b4b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b4a = canon_chain.generate(&mut finalizer).unwrap(); + let b5b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b5a = canon_chain.generate(&mut finalizer).unwrap(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + bc.insert_block(&b1a, vec![]); + bc.insert_block(&b1b, vec![]); + bc.insert_block(&b2a, vec![]); + bc.insert_block(&b2b, vec![]); + bc.insert_block(&b3a, vec![]); + bc.insert_block(&b3b, vec![]); + bc.insert_block(&b4a, vec![]); + bc.insert_block(&b4b, vec![]); + bc.insert_block(&b5a, vec![]); + bc.insert_block(&b5b, vec![]); + + assert_eq!( + [&b4b, &b3b, &b2b].iter().map(|b| BlockView::new(b).header()).collect::>(), + bc.find_uncle_headers(&BlockView::new(&b4a).header_view().sha3(), 3).unwrap() + ); + + // TODO: insert block that already includes one of them as an uncle to check it's not allowed. + } + #[test] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index cc02d84db..1e1a54d57 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -29,7 +29,7 @@ pub type BlockNumber = u64; /// which is non-specific. /// /// Doesn't do all that much on its own. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq)] pub struct Header { // TODO: make all private. /// Parent hash. @@ -70,6 +70,25 @@ pub struct Header { pub bare_hash: RefCell>, } +impl PartialEq for Header { + fn eq(&self, c: &Header) -> bool { + self.parent_hash == c.parent_hash && + self.timestamp == c.timestamp && + self.number == c.number && + self.author == c.author && + self.transactions_root == c.transactions_root && + self.uncles_hash == c.uncles_hash && + self.extra_data == c.extra_data && + self.state_root == c.state_root && + self.receipts_root == c.receipts_root && + self.log_bloom == c.log_bloom && + self.gas_used == c.gas_used && + self.gas_limit == c.gas_limit && + self.difficulty == c.difficulty && + self.seal == c.seal + } +} + impl Default for Header { fn default() -> Self { Header { From 3daa4c6497f48915ad3d156836c24638d1592cbc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 3 Mar 2016 11:39:00 +0100 Subject: [PATCH 340/753] Fix max uncles. --- ethcore/src/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index f5788baba..d05ce51b9 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -220,7 +220,7 @@ impl<'x> OpenBlock<'x> { /// NOTE Will check chain constraints and the uncle number but will NOT check /// that the header itself is actually valid. pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> { - if self.block.base.uncles.len() >= self.engine.maximum_uncle_count() { + if self.block.base.uncles.len() > self.engine.maximum_uncle_count() { return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len()})); } // TODO: check number From df77f51bccf1cd396154207e0084147b26bf9f93 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 3 Mar 2016 11:47:24 +0100 Subject: [PATCH 341/753] History to 30 to pass tests. --- ethcore/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 4ddb40477..bcddec85a 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -200,7 +200,7 @@ pub struct Client { extra_data: RwLock, } -const HISTORY: u64 = 2000000; +const HISTORY: u64 = 30; const CLIENT_DB_VER_STR: &'static str = "4.0"; impl Client { From dadc2a96eafac3a72bef19d84f40357adbcf6032 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 3 Mar 2016 12:39:19 +0100 Subject: [PATCH 342/753] shrink_to_fit after removing hashes. --- ethcore/src/blockchain/blockchain.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 185bcaad3..eac6da6a2 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -759,6 +759,14 @@ impl BlockChain { // TODO: handle block_hashes properly. block_hashes.clear(); + + blocks.shrink_to_fit(); + block_details.shrink_to_fit(); + block_hashes.shrink_to_fit(); + transaction_addresses.shrink_to_fit(); + block_logs.shrink_to_fit(); + blocks_blooms.shrink_to_fit(); + block_receipts.shrink_to_fit(); } if self.cache_size().total() < self.max_cache_size { break; } } From f8dc1f2e3aa96283de3e16d3bbe1e2961b916836 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 3 Mar 2016 12:56:34 +0100 Subject: [PATCH 343/753] Avoid leaking block_details. Fixes #576 --- ethcore/src/blockchain/blockchain.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index eac6da6a2..f412a8240 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -448,7 +448,8 @@ impl BlockChain { let mut write_details = self.block_details.write().unwrap(); for (hash, details) in update.block_details.into_iter() { batch.put_extras(&hash, &details); - write_details.insert(hash, details); + write_details.insert(hash.clone(), details); + self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash)); } let mut write_receipts = self.block_receipts.write().unwrap(); From 8542d651ae8714de4f79342ba9f999dcac8b0988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 4 Mar 2016 11:45:20 +0100 Subject: [PATCH 344/753] Refactoring transactions queue to avoid cloning transactions --- sync/src/transaction_queue.rs | 388 ++++++++++++++++++++-------------- 1 file changed, 224 insertions(+), 164 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index f2e15f955..1bbfbe36d 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -18,121 +18,126 @@ //! Transaction Queue -use std::vec::Vec; use std::cmp::{Ordering}; use std::collections::{HashMap, BTreeSet}; use util::numbers::{Uint, U256}; -use util::hash::{Address}; +use util::hash::{Address, H256}; use util::table::*; use ethcore::transaction::*; #[derive(Clone, Debug)] -struct VerifiedTransaction { - tx: SignedTransaction, - nonce_height: U256 +struct TransactionOrder { + nonce_height: U256, + gas_price: U256, + hash: H256, } -impl VerifiedTransaction { - pub fn new(tx: SignedTransaction, nonce_height: U256) -> VerifiedTransaction { - VerifiedTransaction { - tx: tx, - nonce_height: nonce_height +impl TransactionOrder { + pub fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self { + TransactionOrder { + nonce_height: tx.nonce() - base_nonce, + gas_price: tx.transaction.gas_price, + hash: tx.hash(), } } - - pub fn sender(&self) -> Address { - self.tx.sender().unwrap() - } } -impl Eq for VerifiedTransaction {} -impl PartialEq for VerifiedTransaction { - fn eq(&self, other: &VerifiedTransaction) -> bool { +impl Eq for TransactionOrder {} +impl PartialEq for TransactionOrder { + fn eq(&self, other: &TransactionOrder) -> bool { self.cmp(other) == Ordering::Equal } } -impl PartialOrd for VerifiedTransaction { - fn partial_cmp(&self, other: &VerifiedTransaction) -> Option { +impl PartialOrd for TransactionOrder { + fn partial_cmp(&self, other: &TransactionOrder) -> Option { Some(self.cmp(other)) } } -impl Ord for VerifiedTransaction { - fn cmp(&self, b: &VerifiedTransaction) -> Ordering { +impl Ord for TransactionOrder { + fn cmp(&self, b: &TransactionOrder) -> Ordering { // First check nonce_height if self.nonce_height != b.nonce_height { return self.nonce_height.cmp(&b.nonce_height); } // Then compare gas_prices - let a_gas = self.tx.gas_price; - let b_gas = b.tx.gas_price; + let a_gas = self.gas_price; + let b_gas = b.gas_price; if a_gas != b_gas { return a_gas.cmp(&b_gas); } - // Compare nonce - let a_nonce = self.tx.nonce; - let b_nonce = b.tx.nonce; - if a_nonce != b_nonce { - return a_nonce.cmp(&b_nonce); - } - - // and senders - let a_sender = self.sender(); - let b_sender = b.sender(); - a_sender.cmp(&b_sender) + // Compare hashes + self.hash.cmp(&b.hash) } } -struct TransactionsByPriorityAndAddress { - priority: BTreeSet, - address: Table, +struct VerifiedTransaction { + transaction: SignedTransaction +} +impl VerifiedTransaction { + fn new(transaction: SignedTransaction) -> Self { + VerifiedTransaction { + transaction: transaction + } + } + + fn hash(&self) -> H256 { + self.transaction.hash() + } + + fn nonce(&self) -> U256 { + self.transaction.nonce + } + + fn sender(&self) -> Address { + self.transaction.sender().unwrap() + } +} + +struct TransactionSet { + by_priority: BTreeSet, + by_address: Table, limit: usize, } -impl TransactionsByPriorityAndAddress { - fn insert(&mut self, address: Address, nonce: U256, verified_tx: VerifiedTransaction) { - self.priority.insert(verified_tx.clone()); - self.address.insert(address, nonce, verified_tx); +impl TransactionSet { + fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) { + self.by_priority.insert(order.clone()); + self.by_address.insert(sender, nonce, order); } - fn enforce_limit(&mut self) { - let len = self.priority.len(); + fn enforce_limit(&mut self, by_hash: &HashMap) { + let len = self.by_priority.len(); if len <= self.limit { return; } - let to_remove : Vec = { - self.priority + let to_drop : Vec<&VerifiedTransaction> = { + self.by_priority .iter() .skip(self.limit) - .map(|v_tx| v_tx.tx.clone()) + .map(|order| by_hash.get(&order.hash).expect("Inconsistency in queue detected.")) .collect() }; - for tx in to_remove { - self.remove(&tx); + for tx in to_drop { + self.drop(&tx.sender(), &tx.nonce()); } } - fn remove_by_address(&mut self, sender: &Address, nonce: &U256) -> Option { - if let Some(verified_tx) = self.address.remove(sender, nonce) { - self.priority.remove(&verified_tx); - return Some(verified_tx); + fn drop(&mut self, sender: &Address, nonce: &U256) -> Option { + if let Some(tx_order) = self.by_address.remove(sender, nonce) { + self.by_priority.remove(&tx_order); + return Some(tx_order); } None } - fn remove(&mut self, tx: &SignedTransaction) -> Option { - // First find the transaction by address - let address = tx.sender().unwrap(); - self.remove_by_address(&address, &tx.nonce) - } - fn clear(&mut self) { - self.priority.clear(); - self.address.clear(); + self.by_priority.clear(); + self.by_address.clear(); } } @@ -148,9 +153,11 @@ pub struct TransactionQueueStatus { /// TransactionQueue implementation pub struct TransactionQueue { /// Priority queue for transactions that can go to block - current: TransactionsByPriorityAndAddress, + current: TransactionSet, /// Priority queue for transactions that has been received but are not yet valid to go to block - future: TransactionsByPriorityAndAddress, + future: TransactionSet, + /// All transactions managed by queue indexed by hash + by_hash: HashMap, /// Last nonce of transaction in current last_nonces: HashMap, /// First nonce of transaction in current (used to determine priority) @@ -165,20 +172,21 @@ impl TransactionQueue { /// Create new instance of this Queue with specified limits pub fn with_limits(current_limit: usize, future_limit: usize) -> Self { - let current = TransactionsByPriorityAndAddress { - address: Table::new(), - priority: BTreeSet::new(), + let current = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), limit: current_limit, }; - let future = TransactionsByPriorityAndAddress { - address: Table::new(), - priority: BTreeSet::new(), + let future = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), limit: future_limit, }; TransactionQueue { current: current, future: future, + by_hash: HashMap::new(), last_nonces: HashMap::new(), first_nonces: HashMap::new(), } @@ -187,8 +195,8 @@ impl TransactionQueue { /// Returns current status for this queue pub fn status(&self) -> TransactionQueueStatus { TransactionQueueStatus { - pending: self.current.priority.len(), - future: self.future.priority.len(), + pending: self.current.by_priority.len(), + future: self.future.by_priority.len(), } } @@ -203,101 +211,107 @@ impl TransactionQueue { /// Add signed transaction to queue to be verified and imported pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) where T: Fn(&Address) -> U256 { - self.import_tx(tx, fetch_nonce); + self.import_tx(VerifiedTransaction::new(tx), fetch_nonce); } - /// Removes all transactions in given slice + /// Removes all transactions identified by hashes given in slice /// /// If gap is introduced marks subsequent transactions as future - pub fn remove_all(&mut self, txs: &[SignedTransaction]) { + pub fn remove_all(&mut self, txs: &[H256]) { for tx in txs { self.remove(&tx); } } - /// Removes transaction from queue. + /// Removes transaction identified by hashes from queue. /// /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, tx: &SignedTransaction) { + pub fn remove(&mut self, hash: &H256) { + let transaction = self.by_hash.remove(hash); + if transaction.is_none() { + // We don't know this transaction + return; + } + let transaction = transaction.unwrap(); + let sender = transaction.sender(); + let nonce = transaction.nonce(); + + // Remove from future + self.future.drop(&sender, &nonce); + // Remove from current - let removed = self.current.remove(tx); - if let Some(verified_tx) = removed { - let sender = verified_tx.sender(); - - // Are there any other transactions from this sender? - if !self.current.address.has_row(&sender) { - // Clear last & first nonces - self.last_nonces.remove(&sender); - self.first_nonces.remove(&sender); - return; - } - - // Let's find those with higher nonce (TODO [todr] optimize?) - let to_move_to_future = { - let row_map = self.current.address.row(&sender).unwrap(); - let tx_nonce = verified_tx.tx.nonce; - let mut to_future = Vec::new(); - let mut highest = U256::zero(); - let mut lowest = tx_nonce.clone(); - - // Search nonces to remove and track lowest and highest - for (nonce, _) in row_map.iter() { - if nonce > &tx_nonce { - to_future.push(nonce.clone()); - } else if nonce > &highest { - highest = nonce.clone(); - } else if nonce < &lowest { - lowest = nonce.clone(); - } - } - - // Update first_nonces and last_nonces - if highest == U256::zero() { - self.last_nonces.remove(&sender); - } else { - self.last_nonces.insert(sender.clone(), highest); - } - - if lowest == tx_nonce { - self.first_nonces.remove(&sender); - } else { - self.first_nonces.insert(sender.clone(), lowest); - } - - // return to future - to_future - }; - - for k in to_move_to_future { - if let Some(v) = self.current.remove_by_address(&sender, &k) { - self.future.insert(sender.clone(), v.tx.nonce, v); - } - } - self.future.enforce_limit(); + let order = self.current.drop(&sender, &nonce); + if order.is_none() { return; } - // Remove from future - { - let sender = tx.sender().unwrap(); - if let Some(_) = self.future.remove_by_address(&sender, &tx.nonce) { - return; + // Are there any other transactions from this sender? + if !self.current.by_address.has_row(&sender) { + // Clear last & first nonces + self.last_nonces.remove(&sender); + self.first_nonces.remove(&sender); + return; + } + + // Let's find those with higher nonce (TODO [todr] optimize?) + let to_move_to_future = { + let row_map = self.current.by_address.row(&sender).unwrap(); + let mut to_future = Vec::new(); + let mut highest = U256::zero(); + let mut lowest = nonce.clone(); + + // Search nonces to remove and track lowest and highest + for (current_nonce, _) in row_map.iter() { + if current_nonce > &nonce { + to_future.push(current_nonce.clone()); + } else if current_nonce > &highest { + highest = current_nonce.clone(); + } else if current_nonce < &lowest { + lowest = current_nonce.clone(); + } + } + + // Update first_nonces and last_nonces + if highest == U256::zero() { + self.last_nonces.remove(&sender); + } else { + self.last_nonces.insert(sender.clone(), highest); + } + + if lowest == nonce { + self.first_nonces.remove(&sender); + } else { + self.first_nonces.insert(sender.clone(), lowest); + } + + // return to future + to_future + }; + + for k in to_move_to_future { + if let Some(v) = self.current.drop(&sender, &k) { + // TODO [todr] Recalculate height? + self.future.insert(sender.clone(), k, v); } } + self.future.enforce_limit(&self.by_hash); } /// Returns top transactions from the queue pub fn top_transactions(&self, size: usize) -> Vec { - self.current.priority + self.current.by_priority .iter() .take(size) - .map(|t| t.tx.clone()).collect() + .map(|t| self.by_hash.get(&t.hash).expect("Transaction Queue Inconsistency")) + .map(|t| t.transaction.clone()) + .collect() } /// Removes all elements (in any state) from the queue pub fn clear(&mut self) { self.current.clear(); self.future.clear(); + self.by_hash.clear(); self.last_nonces.clear(); self.first_nonces.clear(); } @@ -305,31 +319,30 @@ impl TransactionQueue { fn move_future_txs(&mut self, address: Address, current_nonce: U256, first_nonce: U256) -> Option { let mut current_nonce = current_nonce + U256::one(); { - let txs_by_nonce = self.future.address.row_mut(&address); - if let None = txs_by_nonce { + let by_nonce = self.future.by_address.row_mut(&address); + if let None = by_nonce { return None; } - let mut txs_by_nonce = txs_by_nonce.unwrap(); - - while let Some(tx) = txs_by_nonce.remove(¤t_nonce) { - // remove also from priority - self.future.priority.remove(&tx); + let mut by_nonce = by_nonce.unwrap(); + while let Some(order) = by_nonce.remove(¤t_nonce) { + // remove also from priority and hash + self.future.by_priority.remove(&order); // Put to current - let height = current_nonce - first_nonce; - let verified_tx = VerifiedTransaction::new(tx.tx, U256::from(height)); - self.current.insert(address.clone(), verified_tx.tx.nonce, verified_tx); + let transaction = self.by_hash.get(&order.hash).expect("TransactionQueue Inconsistency"); + let order = TransactionOrder::for_transaction(transaction, first_nonce); + self.current.insert(address.clone(), transaction.nonce(), order); current_nonce = current_nonce + U256::one(); } } - self.future.address.clear_if_empty(&address); + self.future.by_address.clear_if_empty(&address); // Returns last inserted nonce Some(current_nonce - U256::one()) } - fn import_tx(&mut self, tx: SignedTransaction, fetch_nonce: &T) + fn import_tx(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) where T: Fn(&Address) -> U256 { - let nonce = tx.nonce; - let address = tx.sender().unwrap(); + let nonce = tx.nonce(); + let address = tx.sender(); let next_nonce = U256::one() + self.last_nonces .get(&address) @@ -338,11 +351,12 @@ impl TransactionQueue { // Check height if nonce > next_nonce { - let height = nonce - next_nonce; - let verified_tx = VerifiedTransaction::new(tx, height); + let order = TransactionOrder::for_transaction(&tx, next_nonce); + // Insert to by_hash + self.by_hash.insert(tx.hash(), tx); // We have a gap - put to future - self.future.insert(address, nonce, verified_tx); - self.future.enforce_limit(); + self.future.insert(address, nonce, order); + self.future.enforce_limit(&self.by_hash); return; } else if next_nonce > nonce { // Droping transaction @@ -354,29 +368,34 @@ impl TransactionQueue { .cloned() .unwrap_or_else(|| nonce.clone()); - let height = nonce - first_nonce; - let verified_tx = VerifiedTransaction::new(tx, height); + let order = TransactionOrder::for_transaction(&tx, first_nonce); + // Insert to by_hash + self.by_hash.insert(tx.hash(), tx); + // Insert to current - self.current.insert(address.clone(), nonce, verified_tx); + self.current.insert(address.clone(), nonce, order); // But maybe there are some more items waiting in future? let new_last_nonce = self.move_future_txs(address.clone(), nonce, first_nonce); self.first_nonces.insert(address.clone(), first_nonce); self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); // Enforce limit - self.current.enforce_limit(); + self.current.enforce_limit(&self.by_hash); } } + #[cfg(test)] mod test { extern crate rustc_serialize; use self::rustc_serialize::hex::FromHex; - + use std::collections::{HashMap, BTreeSet}; use util::crypto::KeyPair; use util::numbers::{U256, Uint}; use util::hash::{Address}; + use util::table::*; use ethcore::transaction::*; use super::*; + use super::{TransactionSet, TransactionOrder, VerifiedTransaction}; fn new_unsigned_tx(nonce: U256) -> Transaction { Transaction { @@ -408,6 +427,46 @@ mod test { (tx.sign(secret), tx2.sign(secret)) } + #[test] + fn should_create_transaction_set() { + // given + let mut set = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), + limit: 1 + }; + let (tx1, tx2) = new_txs(U256::from(1)); + let tx1 = VerifiedTransaction::new(tx1); + let tx2 = VerifiedTransaction::new(tx2); + let by_hash = { + let mut x = HashMap::new(); + let tx1 = VerifiedTransaction::new(tx1.transaction.clone()); + let tx2 = VerifiedTransaction::new(tx2.transaction.clone()); + x.insert(tx1.hash(), tx1); + x.insert(tx2.hash(), tx2); + x + }; + // Insert both transactions + let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + set.insert(tx1.sender(), tx1.nonce(), order1.clone()); + let order2 = TransactionOrder::for_transaction(&tx2, U256::zero()); + set.insert(tx2.sender(), tx2.nonce(), order2.clone()); + assert_eq!(set.by_priority.len(), 2); + assert_eq!(set.by_address.len(), 2); + + // when + set.enforce_limit(&by_hash); + + // then + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + assert_eq!(set.by_priority.iter().next().unwrap().clone(), order1); + set.clear(); + assert_eq!(set.by_priority.len(), 0); + assert_eq!(set.by_address.len(), 0); + } + + #[test] fn should_import_tx() { // given @@ -495,8 +554,8 @@ mod test { assert_eq!(txq2.status().future, 1); // when - txq2.remove(&tx); - txq2.remove(&tx2); + txq2.remove(&tx.hash()); + txq2.remove(&tx2.hash()); // then @@ -518,7 +577,7 @@ mod test { assert_eq!(txq.status().pending, 3); // when - txq.remove(&tx); + txq.remove(&tx.hash()); // then let stats = txq.status(); @@ -608,14 +667,15 @@ mod test { assert_eq!(txq.status().pending, 2); // when - txq.remove(&tx1); + txq.remove(&tx1.hash()); + assert_eq!(txq.status().pending, 0); assert_eq!(txq.status().future, 1); txq.add(tx1.clone(), &default_nonce); // then let stats = txq.status(); - assert_eq!(stats.pending, 2); assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 2); } From 706ce5dfb62bb0cc5f6c638b037c28c6f78a1e1d Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 4 Mar 2016 11:56:04 +0100 Subject: [PATCH 345/753] verifier trait --- ethcore/src/client.rs | 18 +++++++++--- ethcore/src/verification/canon_verifier.rs | 28 +++++++++++++++++++ ethcore/src/verification/mod.rs | 25 +++++++++++++++++ ethcore/src/verification/noop_verifier.rs | 27 ++++++++++++++++++ .../src/{ => verification}/verification.rs | 6 ++-- ethcore/src/verification/verifier.rs | 23 +++++++++++++++ 6 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 ethcore/src/verification/canon_verifier.rs create mode 100644 ethcore/src/verification/mod.rs create mode 100644 ethcore/src/verification/noop_verifier.rs rename ethcore/src/{ => verification}/verification.rs (99%) create mode 100644 ethcore/src/verification/verifier.rs diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 422f1eaa2..6ae628f8b 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -16,6 +16,7 @@ //! Blockchain database client. +use std::marker::PhantomData; use util::*; use util::panics::*; use blockchain::{BlockChain, BlockProvider}; @@ -188,7 +189,7 @@ impl ClientReport { /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. /// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. -pub struct Client { +pub struct Client where V: Verifier { chain: Arc>, engine: Arc>, state_db: Mutex, @@ -201,14 +202,22 @@ pub struct Client { sealing_block: Mutex>, author: RwLock
, extra_data: RwLock, + verifier: PhantomData } const HISTORY: u64 = 1000; const CLIENT_DB_VER_STR: &'static str = "4.0"; -impl Client { +impl Client { /// Create a new client with given spec and DB path. pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { + Client::::new_with_verifier(config, spec, path, message_channel) + } +} + +impl Client where V: Verifier { + /// Create a new client with given spec and DB path and custom verifier. + pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { let mut dir = path.to_path_buf(); dir.push(H64::from(spec.genesis_header().hash()).hex()); //TODO: sec/fat: pruned/full versioning @@ -240,6 +249,7 @@ impl Client { sealing_block: Mutex::new(None), author: RwLock::new(Address::new()), extra_data: RwLock::new(Vec::new()), + verifier: PhantomData })) } @@ -302,7 +312,7 @@ impl Client { // Final Verification let closed_block = enact_result.unwrap(); - if let Err(e) = verify_block_final(&header, closed_block.block().header()) { + if let Err(e) = V::verify_block_final(&header, closed_block.block().header()) { warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); } @@ -503,7 +513,7 @@ impl Client { // TODO: need MinerService MinerIoHandler -impl BlockChainClient for Client { +impl BlockChainClient for Client where V: Verifier { fn block_header(&self, id: BlockId) -> Option { let chain = self.chain.read().unwrap(); Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) diff --git a/ethcore/src/verification/canon_verifier.rs b/ethcore/src/verification/canon_verifier.rs new file mode 100644 index 000000000..0d9cbc6b6 --- /dev/null +++ b/ethcore/src/verification/canon_verifier.rs @@ -0,0 +1,28 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use error::Error; +use header::Header; +use super::Verifier; +use super::verification; + +pub struct CanonVerifier; + +impl Verifier for CanonVerifier { + fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> { + verification::verify_block_final(expected, got) + } +} diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs new file mode 100644 index 000000000..260121989 --- /dev/null +++ b/ethcore/src/verification/mod.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +pub mod verification; +pub mod verifier; +mod canon_verifier; +mod noop_verifier; + +pub use self::verification::*; +pub use self::verifier::Verifier; +pub use self::canon_verifier::CanonVerifier; +pub use self::noop_verifier::NoopVerifier; diff --git a/ethcore/src/verification/noop_verifier.rs b/ethcore/src/verification/noop_verifier.rs new file mode 100644 index 000000000..8dfd64771 --- /dev/null +++ b/ethcore/src/verification/noop_verifier.rs @@ -0,0 +1,27 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use error::Error; +use header::Header; +use super::Verifier; + +pub struct NoopVerifier; + +impl Verifier for NoopVerifier { + fn verify_block_final(_expected: &Header, _got: &Header) -> Result<(), Error> { + Ok(()) + } +} diff --git a/ethcore/src/verification.rs b/ethcore/src/verification/verification.rs similarity index 99% rename from ethcore/src/verification.rs rename to ethcore/src/verification/verification.rs index f52e2e1e4..fa540e7c6 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -61,7 +61,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { try!(engine.verify_block_unordered(&u, None)); } - // Verify transactions. + // Verify transactions. let mut transactions = Vec::new(); { let v = BlockView::new(&bytes); @@ -141,7 +141,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b let uncle_parent = try!(bc.block_header(&uncle.parent_hash).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash.clone())))); for _ in 0..depth { match bc.block_details(&expected_uncle_parent) { - Some(details) => { + Some(details) => { expected_uncle_parent = details.parent; }, None => break @@ -468,7 +468,7 @@ mod tests { header.number = 9; check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc), InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number })); - + header = good.clone(); let mut bad_uncles = good_uncles.clone(); bad_uncles.push(good_uncle1.clone()); diff --git a/ethcore/src/verification/verifier.rs b/ethcore/src/verification/verifier.rs new file mode 100644 index 000000000..0ffbf3bdd --- /dev/null +++ b/ethcore/src/verification/verifier.rs @@ -0,0 +1,23 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use error::Error; +use header::Header; + +/// Should be used to verify blocks. +pub trait Verifier: Send + Sync { + fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>; +} From 6a57e83509f9f468e477950270b8318d1cec06b0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 14:46:54 +0300 Subject: [PATCH 346/753] json rpc personal service --- rpc/src/v1/impls/mod.rs | 2 + rpc/src/v1/impls/personal.rs | 81 +++++++++++++++++++++++++++++++++++ rpc/src/v1/mod.rs | 4 +- rpc/src/v1/traits/mod.rs | 2 + rpc/src/v1/traits/personal.rs | 41 ++++++++++++++++++ 5 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 rpc/src/v1/impls/personal.rs create mode 100644 rpc/src/v1/traits/personal.rs diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index d9102b1db..10d451e9f 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -28,7 +28,9 @@ macro_rules! take_weak { mod web3; mod eth; mod net; +mod personal; pub use self::web3::Web3Client; pub use self::eth::{EthClient, EthFilterClient}; pub use self::net::NetClient; +pub use self::personal::PersonalClient; diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs new file mode 100644 index 000000000..b97449541 --- /dev/null +++ b/rpc/src/v1/impls/personal.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Net rpc implementation. +use std::sync::{Arc, Weak}; +use jsonrpc_core::*; +use v1::traits::Personal; +use util::keys::store::*; +use util::{Bytes, Address}; +use std::sync::RwLock; + +/// Net rpc implementation. +pub struct PersonalClient { + secret_store: Weak, + unlocked_account: Arc>>, + unlocked_secret: Arc>>, +} + +impl PersonalClient { + /// Creates new PersonalClient + pub fn new(store: &Arc) -> Self { + PersonalClient { + secret_store: Arc::downgrade(store), + unlocked_account: Arc::new(RwLock::new(None)), + unlocked_secret: Arc::new(RwLock::new(None)), + } + } +} + +impl Personal for PersonalClient { + fn accounts(&self, _: Params) -> Result { + let store = take_weak!(self.secret_store); + match store.accounts() { + Ok(account_list) => { + Ok(Value::Array(account_list.iter() + .map(|&(account, _)| Value::String(format!("{:?}", account))) + .collect::>()) + ) + } + Err(_) => Err(Error::internal_error()) + } + } + + fn new_account(&self, _: Params) -> Result { + Err(Error::internal_error()) + } + + fn unlock_account(&self, params: Params) -> Result { + from_params::<(Address, String, u64)>(params).and_then( + |(account, account_pass, _)|{ + let store = take_weak!(self.secret_store); + let secret_id = match store.account(&account) { + None => { return Ok(Value::Bool(false)); } + Some(id) => id + }; + match store.get(&secret_id, &account_pass) { + Ok(secret) => { + *self.unlocked_account.write().unwrap() = Some(account); + *self.unlocked_secret.write().unwrap() = Some(secret); + Ok(Value::Bool(true)) + }, + Err(_) => { + Ok(Value::Bool(false)) + } + } + }) + } +} diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 57f7a944a..104a8b3f0 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Ethcore rpc v1. -//! +//! //! Compliant with ethereum rpc. pub mod traits; @@ -25,5 +25,5 @@ mod types; mod tests; mod helpers; -pub use self::traits::{Web3, Eth, EthFilter, Net}; +pub use self::traits::{Web3, Eth, EthFilter, Personal, Net}; pub use self::impls::*; diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index c9af6dac3..0a95cb050 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -23,7 +23,9 @@ macro_rules! rpc_unimplemented { pub mod web3; pub mod eth; pub mod net; +pub mod personal; pub use self::web3::Web3; pub use self::eth::{Eth, EthFilter}; pub use self::net::Net; +pub use self::personal::Personal; diff --git a/rpc/src/v1/traits/personal.rs b/rpc/src/v1/traits/personal.rs new file mode 100644 index 000000000..0cf72951c --- /dev/null +++ b/rpc/src/v1/traits/personal.rs @@ -0,0 +1,41 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Personal rpc interface. +use std::sync::Arc; +use jsonrpc_core::*; + +/// Personal rpc interface. +pub trait Personal: Sized + Send + Sync + 'static { + + /// Lists all stored accounts + fn accounts(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Creates new account (it becomes new current unlocked account) + fn new_account(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Unlocks specified account for use (can only be one unlocked account at one moment) + fn unlock_account(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Should be used to convert object to io delegate. + fn to_delegate(self) -> IoDelegate { + let mut delegate = IoDelegate::new(Arc::new(self)); + delegate.add_method("personal_listAccounts", Personal::accounts); + delegate.add_method("personal_newAccount", Personal::new_account); + delegate.add_method("personal_unlockAccount", Personal::unlock_account); + delegate + } +} From e17b2a4db8871e9e70917a75e7975d32d652ecb4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 14:48:05 +0300 Subject: [PATCH 347/753] replacing unsafe cell with rwlock --- util/src/keys/directory.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 7178508a2..d0d3393cd 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -461,17 +461,17 @@ enum KeyFileLoadError { pub struct KeyDirectory { /// Directory path for key management. path: String, - cache: RefCell>, - cache_usage: RefCell>, + cache: RwLock>, + cache_usage: RwLock>, } impl KeyDirectory { /// Initializes new cache directory context with a given `path` pub fn new(path: &Path) -> KeyDirectory { KeyDirectory { - cache: RefCell::new(HashMap::new()), + cache: RwLock::new(HashMap::new()), path: path.to_str().expect("Initialized key directory with empty path").to_owned(), - cache_usage: RefCell::new(VecDeque::new()), + cache_usage: RwLock::new(VecDeque::new()), } } @@ -484,7 +484,7 @@ impl KeyDirectory { let json_bytes = json_text.into_bytes(); try!(file.write(&json_bytes)); } - let mut cache = self.cache.borrow_mut(); + let mut cache = self.cache.write().unwrap(); let id = key_file.id.clone(); cache.insert(id.clone(), key_file); Ok(id.clone()) @@ -495,14 +495,14 @@ impl KeyDirectory { pub fn get(&self, id: &Uuid) -> Option { let path = self.key_path(id); { - let mut usage = self.cache_usage.borrow_mut(); + let mut usage = self.cache_usage.write().unwrap(); usage.push_back(id.clone()); } - if !self.cache.borrow().contains_key(id) { + if !self.cache.read().unwrap().contains_key(id) { match KeyDirectory::load_key(&path) { Ok(loaded_key) => { - self.cache.borrow_mut().insert(id.to_owned(), loaded_key); + self.cache.write().unwrap().insert(id.to_owned(), loaded_key); } Err(error) => { warn!(target: "sstore", "error loading key {:?}: {:?}", id, error); @@ -512,7 +512,7 @@ impl KeyDirectory { } // todo: replace with Ref::map when it stabilized to avoid copies - Some(self.cache.borrow().get(id) + Some(self.cache.read().unwrap().get(id) .expect("Key should be there, we have just inserted or checked it.") .clone()) } @@ -524,7 +524,7 @@ impl KeyDirectory { /// Removes keys that never been requested during last `MAX_USAGE_TRACK` times pub fn collect_garbage(&mut self) { - let mut cache_usage = self.cache_usage.borrow_mut(); + let mut cache_usage = self.cache_usage.write().unwrap(); let total_usages = cache_usage.len(); let untracked_usages = max(total_usages as i64 - MAX_CACHE_USAGE_TRACK as i64, 0) as usize; @@ -532,31 +532,31 @@ impl KeyDirectory { cache_usage.drain(..untracked_usages); } - if self.cache.borrow().len() <= MAX_CACHE_USAGE_TRACK { return; } + if self.cache.read().unwrap().len() <= MAX_CACHE_USAGE_TRACK { return; } let uniqs: HashSet<&Uuid> = cache_usage.iter().collect(); let removes:Vec = { - let cache = self.cache.borrow(); + let cache = self.cache.read().unwrap(); cache.keys().cloned().filter(|key| !uniqs.contains(key)).collect() }; if removes.is_empty() { return; } - let mut cache = self.cache.borrow_mut(); + let mut cache = self.cache.write().unwrap(); for key in removes { cache.remove(&key); } } /// Reports how many keys are currently cached. pub fn cache_size(&self) -> usize { - self.cache.borrow().len() + self.cache.read().unwrap().len() } /// Removes key file from key directory pub fn delete(&mut self, id: &Uuid) -> Result<(), ::std::io::Error> { let path = self.key_path(id); - if !self.cache.borrow().contains_key(id) { + if !self.cache.read().unwrap().contains_key(id) { return match fs::remove_file(&path) { Ok(_) => { - self.cache.borrow_mut().remove(&id); + self.cache.write().unwrap().remove(&id); Ok(()) }, Err(e) => Err(e) From 4f62e80de753d40e821540034771123c5da895e0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 14:53:18 +0300 Subject: [PATCH 348/753] name fix --- rpc/src/v1/impls/personal.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index b97449541..d7066c082 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Net rpc implementation. +//! Account management (personal) rpc implementation use std::sync::{Arc, Weak}; use jsonrpc_core::*; use v1::traits::Personal; @@ -22,7 +22,7 @@ use util::keys::store::*; use util::{Bytes, Address}; use std::sync::RwLock; -/// Net rpc implementation. +/// Account management (personal) rpc implementation. pub struct PersonalClient { secret_store: Weak, unlocked_account: Arc>>, From 0d01099f44374d3bc10515b0a215d3eed08dd9c4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 16:23:00 +0300 Subject: [PATCH 349/753] moving unlock logics to secret-store itself --- Cargo.lock | 10 ++++++ rpc/src/v1/impls/personal.rs | 45 +++++++++++++-------------- util/Cargo.toml | 1 + util/src/keys/store.rs | 60 ++++++++++++++++++++++++++++++++++-- util/src/lib.rs | 1 + 5 files changed, 90 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03b8092a0..17f2d87d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,15 @@ name = "cfg-if" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clippy" version = "0.0.44" @@ -236,6 +245,7 @@ version = "0.9.99" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", + "chrono 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index d7066c082..48e1b1c6a 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -19,30 +19,27 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; use v1::traits::Personal; use util::keys::store::*; -use util::{Bytes, Address}; +use util::Address; use std::sync::RwLock; /// Account management (personal) rpc implementation. pub struct PersonalClient { - secret_store: Weak, - unlocked_account: Arc>>, - unlocked_secret: Arc>>, + secret_store: Weak>, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(store: &Arc) -> Self { + pub fn new(store: &Arc>) -> Self { PersonalClient { secret_store: Arc::downgrade(store), - unlocked_account: Arc::new(RwLock::new(None)), - unlocked_secret: Arc::new(RwLock::new(None)), } } } impl Personal for PersonalClient { fn accounts(&self, _: Params) -> Result { - let store = take_weak!(self.secret_store); + let store_wk = take_weak!(self.secret_store); + let store = store_wk.read().unwrap(); match store.accounts() { Ok(account_list) => { Ok(Value::Array(account_list.iter() @@ -54,27 +51,27 @@ impl Personal for PersonalClient { } } - fn new_account(&self, _: Params) -> Result { - Err(Error::internal_error()) + fn new_account(&self, params: Params) -> Result { + from_params::<(String, )>(params).and_then( + |(pass, )| { + let store_wk = take_weak!(self.secret_store); + let mut store = store_wk.write().unwrap(); + match store.new_account(&pass) { + Ok(address) => Ok(Value::String(format!("{:?}", address))), + Err(_) => Err(Error::internal_error()) + } + } + ) } fn unlock_account(&self, params: Params) -> Result { from_params::<(Address, String, u64)>(params).and_then( |(account, account_pass, _)|{ - let store = take_weak!(self.secret_store); - let secret_id = match store.account(&account) { - None => { return Ok(Value::Bool(false)); } - Some(id) => id - }; - match store.get(&secret_id, &account_pass) { - Ok(secret) => { - *self.unlocked_account.write().unwrap() = Some(account); - *self.unlocked_secret.write().unwrap() = Some(secret); - Ok(Value::Bool(true)) - }, - Err(_) => { - Ok(Value::Bool(false)) - } + let store_wk = take_weak!(self.secret_store); + let store = store_wk.read().unwrap(); + match store.unlock_account(&account, &account_pass) { + Ok(_) => Ok(Value::Bool(true)), + Err(_) => Ok(Value::Bool(false)), } }) } diff --git a/util/Cargo.toml b/util/Cargo.toml index 0c7df3f40..9c5cb3fe3 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -36,6 +36,7 @@ libc = "0.2.7" vergen = "0.1" target_info = "0.1" bigint = { path = "bigint" } +chrono = "0.2" [features] default = [] diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index c4fa377f9..99cbf751b 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -22,6 +22,7 @@ use rcrypto::pbkdf2::*; use rcrypto::scrypt::*; use rcrypto::hmac::*; use crypto; +use chrono::*; const KEY_LENGTH: u32 = 32; const KEY_ITERATIONS: u32 = 10240; @@ -57,7 +58,13 @@ pub enum EncryptedHashMapError { /// Represent service for storing encrypted arbitrary data pub struct SecretStore { - directory: KeyDirectory + directory: KeyDirectory, + unlocks: RwLock> +} + +struct AccountUnlock { + secret: H256, + expires: DateTime, } impl SecretStore { @@ -72,7 +79,8 @@ impl SecretStore { /// new instance of Secret Store in specific directory pub fn new_in(path: &Path) -> SecretStore { SecretStore { - directory: KeyDirectory::new(path) + directory: KeyDirectory::new(path), + unlocks: RwLock::new(HashMap::new()) } } @@ -120,9 +128,37 @@ impl SecretStore { #[cfg(test)] fn new_test(path: &::devtools::RandomTempPath) -> SecretStore { SecretStore { - directory: KeyDirectory::new(path.as_path()) + directory: KeyDirectory::new(path.as_path()), + unlocks: RwLock::new(HashMap::new()) } } + + /// Unlocks account for use + pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier)); + let secret = try!(self.get(&secret_id, pass)); + { + let mut write_lock = self.unlocks.write().unwrap(); + let mut unlock = write_lock.entry(*account) + .or_insert_with(|| AccountUnlock { secret: secret, expires: UTC::now() }); + unlock.secret = secret; + unlock.expires = UTC::now() + Duration::minutes(20); + } + Ok(()) + } + + /// Creates new account + pub fn new_account(&mut self, pass: &str) -> Result { + let secret = H256::random(); + let key_id = H128::random(); + self.insert(key_id.clone(), secret, pass); + + let mut key_file = self.directory.get(&key_id).expect("the key was just inserted"); + let address = Address::random(); + key_file.account = Some(address); + try!(self.directory.save(key_file)); + Ok(address) + } } fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) { @@ -369,6 +405,24 @@ mod tests { assert_eq!(4, sstore.directory.list().unwrap().len()) } + #[test] + fn can_create_account() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + sstore.new_account("123").unwrap(); + assert_eq!(1, sstore.accounts().unwrap().len()); + } + + #[test] + fn can_unlock_account() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + let address = sstore.new_account("123").unwrap(); + + let secret = sstore.unlock_account(&address, "123"); + assert!(secret.is_ok()); + } + #[test] fn can_import_account() { use keys::directory::{KeyFileContent, KeyFileCrypto}; diff --git a/util/src/lib.rs b/util/src/lib.rs index 8594e6f40..a50ba8da4 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -111,6 +111,7 @@ extern crate rustc_version; extern crate target_info; extern crate vergen; extern crate bigint; +extern crate chrono; pub mod standard; #[macro_use] From ae51d99fb89e3311196a5d2f491812845169d834 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 16:40:17 +0300 Subject: [PATCH 350/753] [ci skip] trailing commas --- util/src/keys/store.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 99cbf751b..f05b8dec4 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -59,7 +59,7 @@ pub enum EncryptedHashMapError { /// Represent service for storing encrypted arbitrary data pub struct SecretStore { directory: KeyDirectory, - unlocks: RwLock> + unlocks: RwLock>, } struct AccountUnlock { @@ -80,7 +80,7 @@ impl SecretStore { pub fn new_in(path: &Path) -> SecretStore { SecretStore { directory: KeyDirectory::new(path), - unlocks: RwLock::new(HashMap::new()) + unlocks: RwLock::new(HashMap::new()), } } @@ -129,7 +129,7 @@ impl SecretStore { fn new_test(path: &::devtools::RandomTempPath) -> SecretStore { SecretStore { directory: KeyDirectory::new(path.as_path()), - unlocks: RwLock::new(HashMap::new()) + unlocks: RwLock::new(HashMap::new()), } } From b320ff46020ff8a3f517901969d17a28fd040de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 4 Mar 2016 15:02:11 +0100 Subject: [PATCH 351/753] Getting rid of first_nonces (we can fetch it from state) --- sync/src/transaction_queue.rs | 76 ++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 1bbfbe36d..a12d75ed4 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -158,10 +158,8 @@ pub struct TransactionQueue { future: TransactionSet, /// All transactions managed by queue indexed by hash by_hash: HashMap, - /// Last nonce of transaction in current + /// Last nonce of transaction in current (to quickly check next expected transaction) last_nonces: HashMap, - /// First nonce of transaction in current (used to determine priority) - first_nonces: HashMap, } impl TransactionQueue { @@ -188,7 +186,6 @@ impl TransactionQueue { future: future, by_hash: HashMap::new(), last_nonces: HashMap::new(), - first_nonces: HashMap::new(), } } @@ -217,16 +214,18 @@ impl TransactionQueue { /// Removes all transactions identified by hashes given in slice /// /// If gap is introduced marks subsequent transactions as future - pub fn remove_all(&mut self, txs: &[H256]) { + pub fn remove_all(&mut self, txs: &[H256], fetch_nonce: T) + where T: Fn(&Address) -> U256 { for tx in txs { - self.remove(&tx); + self.remove(&tx, &fetch_nonce); } } /// Removes transaction identified by hashes from queue. /// /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, hash: &H256) { + pub fn remove(&mut self, hash: &H256, fetch_nonce: &T) + where T: Fn(&Address) -> U256 { let transaction = self.by_hash.remove(hash); if transaction.is_none() { // We don't know this transaction @@ -249,11 +248,10 @@ impl TransactionQueue { if !self.current.by_address.has_row(&sender) { // Clear last & first nonces self.last_nonces.remove(&sender); - self.first_nonces.remove(&sender); return; } - // Let's find those with higher nonce (TODO [todr] optimize?) + // Let's find those with higher nonce that should be moved to future (TODO [todr] optimize?) let to_move_to_future = { let row_map = self.current.by_address.row(&sender).unwrap(); let mut to_future = Vec::new(); @@ -271,23 +269,17 @@ impl TransactionQueue { } } - // Update first_nonces and last_nonces + // Update last_nonces if highest == U256::zero() { self.last_nonces.remove(&sender); } else { self.last_nonces.insert(sender.clone(), highest); } - if lowest == nonce { - self.first_nonces.remove(&sender); - } else { - self.first_nonces.insert(sender.clone(), lowest); - } - - // return to future to_future }; + // Move to future for k in to_move_to_future { if let Some(v) = self.current.drop(&sender, &k) { // TODO [todr] Recalculate height? @@ -295,6 +287,8 @@ impl TransactionQueue { } } self.future.enforce_limit(&self.by_hash); + + // But maybe some transactions } /// Returns top transactions from the queue @@ -313,7 +307,6 @@ impl TransactionQueue { self.future.clear(); self.by_hash.clear(); self.last_nonces.clear(); - self.first_nonces.clear(); } fn move_future_txs(&mut self, address: Address, current_nonce: U256, first_nonce: U256) -> Option { @@ -344,9 +337,10 @@ impl TransactionQueue { let nonce = tx.nonce(); let address = tx.sender(); - let next_nonce = U256::one() + self.last_nonces + let next_nonce = self.last_nonces .get(&address) .cloned() + .map(|n| n + U256::one()) .unwrap_or_else(|| fetch_nonce(&address)); // Check height @@ -363,20 +357,15 @@ impl TransactionQueue { return; } - let first_nonce = self.first_nonces - .get(&address) - .cloned() - .unwrap_or_else(|| nonce.clone()); - - let order = TransactionOrder::for_transaction(&tx, first_nonce); + let base_nonce = fetch_nonce(&address); + let order = TransactionOrder::for_transaction(&tx, base_nonce); // Insert to by_hash self.by_hash.insert(tx.hash(), tx); // Insert to current self.current.insert(address.clone(), nonce, order); // But maybe there are some more items waiting in future? - let new_last_nonce = self.move_future_txs(address.clone(), nonce, first_nonce); - self.first_nonces.insert(address.clone(), first_nonce); + let new_last_nonce = self.move_future_txs(address.clone(), nonce, base_nonce); self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); // Enforce limit self.current.enforce_limit(&self.by_hash); @@ -414,7 +403,7 @@ mod test { } fn default_nonce(_address: &Address) -> U256 { - U256::from(122) + U256::from(123) } fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) { @@ -554,8 +543,8 @@ mod test { assert_eq!(txq2.status().future, 1); // when - txq2.remove(&tx.hash()); - txq2.remove(&tx2.hash()); + txq2.remove(&tx.hash(), &default_nonce); + txq2.remove(&tx2.hash(), &default_nonce); // then @@ -577,7 +566,7 @@ mod test { assert_eq!(txq.status().pending, 3); // when - txq.remove(&tx.hash()); + txq.remove(&tx.hash(), &default_nonce); // then let stats = txq.status(); @@ -645,7 +634,7 @@ mod test { fn should_drop_transactions_with_old_nonces() { let mut txq = TransactionQueue::new(); let tx = new_tx(); - let last_nonce = tx.nonce.clone(); + let last_nonce = tx.nonce.clone() + U256::one(); let fetch_last_nonce = |_a: &Address| last_nonce; // when @@ -667,7 +656,7 @@ mod test { assert_eq!(txq.status().pending, 2); // when - txq.remove(&tx1.hash()); + txq.remove(&tx1.hash(), &default_nonce); assert_eq!(txq.status().pending, 0); assert_eq!(txq.status().future, 1); txq.add(tx1.clone(), &default_nonce); @@ -676,7 +665,28 @@ mod test { let stats = txq.status(); assert_eq!(stats.future, 0); assert_eq!(stats.pending, 2); + } + #[test] + fn should_not_move_to_future_if_state_nonce_is_higher() { + // given + let next_nonce = |a: &Address| default_nonce(a) + U256::one(); + let mut txq = TransactionQueue::new(); + let (tx, tx2) = new_txs(U256::from(1)); + let tx3 = new_tx(); + txq.add(tx2.clone(), &default_nonce); + assert_eq!(txq.status().future, 1); + txq.add(tx3.clone(), &default_nonce); + txq.add(tx.clone(), &default_nonce); + assert_eq!(txq.status().pending, 3); + + // when + txq.remove(&tx.hash(), &next_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 2); } } From 677c3996b9aca31debd3059b1e3e575dce99ffb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 4 Mar 2016 16:09:05 +0100 Subject: [PATCH 352/753] Taking expected nonce from state into consideration when removing txs --- sync/src/transaction_queue.rs | 79 ++++++++++++++++------------------- 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index a12d75ed4..4f5622a2f 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -34,13 +34,18 @@ struct TransactionOrder { } impl TransactionOrder { - pub fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self { + fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self { TransactionOrder { nonce_height: tx.nonce() - base_nonce, gas_price: tx.transaction.gas_price, hash: tx.hash(), } } + + fn update_height(mut self, nonce: U256, base_nonce: U256) -> Self { + self.nonce_height = nonce - base_nonce; + self + } } impl Eq for TransactionOrder {} @@ -235,6 +240,7 @@ impl TransactionQueue { let sender = transaction.sender(); let nonce = transaction.nonce(); + println!("Removing tx: {:?}", transaction.transaction); // Remove from future self.future.drop(&sender, &nonce); @@ -244,51 +250,35 @@ impl TransactionQueue { return; } - // Are there any other transactions from this sender? - if !self.current.by_address.has_row(&sender) { - // Clear last & first nonces - self.last_nonces.remove(&sender); - return; - } + // Let's remove transactions where tx.nonce < current_nonce + // and if there are any future transactions matching current_nonce+1 - move to current + let current_nonce = fetch_nonce(&sender); + // We will either move transaction to future or remove it completely + // so there will be no transactions from this sender in current + self.last_nonces.remove(&sender); - // Let's find those with higher nonce that should be moved to future (TODO [todr] optimize?) - let to_move_to_future = { - let row_map = self.current.by_address.row(&sender).unwrap(); - let mut to_future = Vec::new(); - let mut highest = U256::zero(); - let mut lowest = nonce.clone(); - - // Search nonces to remove and track lowest and highest - for (current_nonce, _) in row_map.iter() { - if current_nonce > &nonce { - to_future.push(current_nonce.clone()); - } else if current_nonce > &highest { - highest = current_nonce.clone(); - } else if current_nonce < &lowest { - lowest = current_nonce.clone(); - } - } - - // Update last_nonces - if highest == U256::zero() { - self.last_nonces.remove(&sender); - } else { - self.last_nonces.insert(sender.clone(), highest); - } - - to_future + let all_nonces_from_sender = match self.current.by_address.row(&sender) { + Some(row_map) => row_map.keys().cloned().collect::>(), + None => vec![], }; - // Move to future - for k in to_move_to_future { - if let Some(v) = self.current.drop(&sender, &k) { - // TODO [todr] Recalculate height? - self.future.insert(sender.clone(), k, v); + for k in all_nonces_from_sender { + // Goes to future or is removed + let order = self.current.drop(&sender, &k).unwrap(); + if k >= current_nonce { + println!("Moving to future: {:?}", order); + self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); + } else { + self.by_hash.remove(&order.hash); } } self.future.enforce_limit(&self.by_hash); - // But maybe some transactions + // And now lets check if there is some chain of transactions in future + // that should be placed in current + if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce - U256::one(), current_nonce) { + self.last_nonces.insert(sender, new_current_top); + } } /// Returns top transactions from the queue @@ -310,6 +300,7 @@ impl TransactionQueue { } fn move_future_txs(&mut self, address: Address, current_nonce: U256, first_nonce: U256) -> Option { + println!("Moving from future for: {:?} base: {:?}", current_nonce, first_nonce); let mut current_nonce = current_nonce + U256::one(); { let by_nonce = self.future.by_address.row_mut(&address); @@ -321,9 +312,9 @@ impl TransactionQueue { // remove also from priority and hash self.future.by_priority.remove(&order); // Put to current - let transaction = self.by_hash.get(&order.hash).expect("TransactionQueue Inconsistency"); - let order = TransactionOrder::for_transaction(transaction, first_nonce); - self.current.insert(address.clone(), transaction.nonce(), order); + println!("Moved: {:?}", order); + let order = order.update_height(current_nonce.clone(), first_nonce); + self.current.insert(address.clone(), current_nonce, order); current_nonce = current_nonce + U256::one(); } } @@ -340,9 +331,9 @@ impl TransactionQueue { let next_nonce = self.last_nonces .get(&address) .cloned() - .map(|n| n + U256::one()) - .unwrap_or_else(|| fetch_nonce(&address)); + .map_or_else(|| fetch_nonce(&address), |n| n + U256::one()); + println!("Expected next: {:?}, got: {:?}", next_nonce, nonce); // Check height if nonce > next_nonce { let order = TransactionOrder::for_transaction(&tx, next_nonce); From bcaed67eaa0257c8998925287fd2dbc40df12698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 4 Mar 2016 16:48:10 +0100 Subject: [PATCH 353/753] Swapping order of inserting block to chain and commiting to DB to avoid race conditions --- ethcore/src/client.rs | 12 +++++++----- sync/src/transaction_queue.rs | 4 ---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index d442a3d88..fdcd6c057 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -329,18 +329,14 @@ impl Client { bad_blocks.insert(header.hash()); continue; } - let closed_block = self.check_and_close_block(&block); if let Err(_) = closed_block { bad_blocks.insert(header.hash()); break; } - - // Insert block - let closed_block = closed_block.unwrap(); - self.chain.write().unwrap().insert_block(&block.bytes, closed_block.block().receipts().clone()); good_blocks.push(header.hash()); + // Are we committing an era? let ancient = if header.number() >= HISTORY { let n = header.number() - HISTORY; let chain = self.chain.read().unwrap(); @@ -350,10 +346,16 @@ impl Client { }; // Commit results + let closed_block = closed_block.unwrap(); + let receipts = closed_block.block().receipts().clone(); closed_block.drain() .commit(header.number(), &header.hash(), ancient) .expect("State DB commit failed."); + // And update the chain + self.chain.write().unwrap() + .insert_block(&block.bytes, receipts); + self.report.write().unwrap().accrue_block(&block); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); } diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index f551fe435..83665dfda 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -240,7 +240,6 @@ impl TransactionQueue { let sender = transaction.sender(); let nonce = transaction.nonce(); - println!("Removing tx: {:?}", transaction.transaction); // Remove from future self.future.drop(&sender, &nonce); @@ -266,7 +265,6 @@ impl TransactionQueue { // Goes to future or is removed let order = self.current.drop(&sender, &k).unwrap(); if k >= current_nonce { - println!("Moving to future: {:?}", order); self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); } else { self.by_hash.remove(&order.hash); @@ -310,7 +308,6 @@ impl TransactionQueue { // remove also from priority and hash self.future.by_priority.remove(&order); // Put to current - println!("Moved: {:?}", order); let order = order.update_height(current_nonce.clone(), first_nonce); self.current.insert(address.clone(), current_nonce, order); current_nonce = current_nonce + U256::one(); @@ -331,7 +328,6 @@ impl TransactionQueue { .cloned() .map_or_else(|| fetch_nonce(&address), |n| n + U256::one()); - println!("Expected next: {:?}, got: {:?}", next_nonce, nonce); // Check height if nonce > next_nonce { let order = TransactionOrder::for_transaction(&tx, next_nonce); From d59972a9ac7f4cdda4006cdf300470dc07dd9c66 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 20:07:23 +0300 Subject: [PATCH 354/753] deserialization for uint generic --- util/bigint/src/uint.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index a70997dc5..bd57e9d6d 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -778,6 +778,35 @@ macro_rules! construct_uint { } } + impl serde::Deserialize for $name { + fn deserialize(deserializer: &mut D) -> Result<$name, D::Error> + where D: serde::Deserializer { + struct UintVisitor; + + impl serde::de::Visitor for UintVisitor { + type Value = $name; + + fn visit_str(&mut self, value: &str) -> Result where E: serde::Error { + // 0x + len + if value.len() != 2 + $n_words / 8 { + return Err(serde::Error::custom("Invalid length.")); + } + + match $name::from_str(&value[2..]) { + Ok(val) => Ok(val), + Err(_) => { return Err(serde::Error::custom("Invalid length.")); } + } + } + + fn visit_string(&mut self, value: String) -> Result where E: serde::Error { + self.visit_str(value.as_ref()) + } + } + + deserializer.deserialize(UintVisitor) + } + } + impl From for $name { fn from(value: u64) -> $name { let mut ret = [0; $n_words]; From 2e3fb103abbc55d209fb4afbece9e933a54b1a7d Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 20:08:42 +0300 Subject: [PATCH 355/753] extended secret store operations --- util/src/keys/store.rs | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index f05b8dec4..bfb8e6c79 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -56,6 +56,17 @@ pub enum EncryptedHashMapError { InvalidValueFormat(FromBytesError), } +/// Error retrieving value from encrypted hashmap +#[derive(Debug)] +pub enum SigningError { + /// Account passed does not exist + NoAccount, + /// Account passed is not unlocked + AccountNotUnlocked, + /// Invalid secret in store + InvalidSecret +} + /// Represent service for storing encrypted arbitrary data pub struct SecretStore { directory: KeyDirectory, @@ -159,6 +170,26 @@ impl SecretStore { try!(self.directory.save(key_file)); Ok(address) } + + /// Signs message with unlocked account + pub fn sign(&self, account: &Address, message: &H256) -> Result { + let read_lock = self.unlocks.read().unwrap(); + let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); + match crypto::KeyPair::from_secret(unlock.secret) { + Ok(pair) => match pair.sign(message) { + Ok(signature) => Ok(signature), + Err(_) => Err(SigningError::InvalidSecret) + }, + Err(_) => Err(SigningError::InvalidSecret) + } + } + + /// Returns secret for unlocked account + pub fn account_secret(&self, account: &Address) -> Result { + let read_lock = self.unlocks.read().unwrap(); + let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); + Ok(unlock.secret as crypto::Secret) + } } fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) { @@ -423,6 +454,22 @@ mod tests { assert!(secret.is_ok()); } + #[test] + fn can_sign_data() { + let temp = RandomTempPath::create_dir(); + let address = { + let mut sstore = SecretStore::new_test(&temp); + sstore.new_account("334").unwrap() + }; + let signature = { + let sstore = SecretStore::new_test(&temp); + sstore.unlock_account(&address, "334").unwrap(); + sstore.sign(&address, &H256::random()).unwrap() + }; + + assert!(signature != x!(0)); + } + #[test] fn can_import_account() { use keys::directory::{KeyFileContent, KeyFileCrypto}; From c72c27b47ebb3bf5f4be3b4fb862f3f0ef29ff7f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 20:09:21 +0300 Subject: [PATCH 356/753] client integration --- ethcore/src/client.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 6ae628f8b..070513c0a 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -36,6 +36,7 @@ use transaction::LocalizedTransaction; use extras::TransactionAddress; use filter::Filter; use log_entry::LocalizedLogEntry; +use util::keys::store::SecretStore; pub use block_queue::{BlockQueueConfig, BlockQueueInfo}; pub use blockchain::{TreeRoute, BlockChainConfig, CacheSize as BlockChainCacheSize}; @@ -202,7 +203,8 @@ pub struct Client where V: Verifier { sealing_block: Mutex>, author: RwLock
, extra_data: RwLock, - verifier: PhantomData + verifier: PhantomData, + secret_store: Arc>, } const HISTORY: u64 = 1000; @@ -238,6 +240,9 @@ impl Client where V: Verifier { let panic_handler = PanicHandler::new_in_arc(); panic_handler.forward_from(&block_queue); + let secret_store = Arc::new(RwLock::new(SecretStore::new())); + secret_store.write().unwrap().try_import_existing(); + Ok(Arc::new(Client { chain: chain, engine: engine, @@ -249,7 +254,8 @@ impl Client where V: Verifier { sealing_block: Mutex::new(None), author: RwLock::new(Address::new()), extra_data: RwLock::new(Vec::new()), - verifier: PhantomData + verifier: PhantomData, + secret_store: secret_store, })) } @@ -274,6 +280,11 @@ impl Client where V: Verifier { last_hashes } + /// Secret store (key manager) + pub fn secret_store(&self) -> &Arc> { + &self.secret_store + } + fn check_and_close_block(&self, block: &PreverifiedBlock) -> Result { let engine = self.engine.deref().deref(); let header = &block.header; From af5ed8b5f7af5b576fed3181dc03c45fdee50f1b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 20:10:07 +0300 Subject: [PATCH 357/753] rpc-signing-extend --- parity/main.rs | 1 + rpc/src/v1/impls/eth.rs | 17 ++++++++++++++++- rpc/src/v1/impls/personal.rs | 21 ++++++++++----------- rpc/src/v1/types/bytes.rs | 32 ++++++++++++++++++++++++++++++-- rpc/src/v1/types/mod.rs.in | 2 ++ rpc/src/v1/types/transaction.rs | 13 +++++++++++++ 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index b991f36cd..91a884beb 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -157,6 +157,7 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_dom server.add_delegate(EthClient::new(&client, &sync).to_delegate()); server.add_delegate(EthFilterClient::new(&client).to_delegate()); server.add_delegate(NetClient::new(&sync).to_delegate()); + server.add_delegate(PersonalClient::new(&client).to_delegate()); server.start_async(url, cors_domain); } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2313d5114..16b68f90f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -29,7 +29,7 @@ use ethcore::views::*; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; use v1::helpers::{PollFilter, PollManager}; /// Eth rpc implementation. @@ -253,6 +253,21 @@ impl Eth for EthClient { to_value(&true) }) } + + fn send_transaction(&self, params: Params) -> Result { + from_params::<(TransactionRequest, )>(params) + .and_then(|(transaction_request, )| { + let client = take_weak!(self.client); + let store = client.secret_store().read().unwrap(); + match store.account_secret(&transaction_request.from) { + Ok(_) => { + // todo: actually sign and push to queue transaction here + Ok(Value::Bool(true)) + }, + Err(_) => { Ok(Value::Bool(false ))} + } + }) + } } /// Eth filter rpc implementation. diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 48e1b1c6a..a2788b9d9 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -18,28 +18,27 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; use v1::traits::Personal; -use util::keys::store::*; use util::Address; -use std::sync::RwLock; +use ethcore::client::Client; /// Account management (personal) rpc implementation. pub struct PersonalClient { - secret_store: Weak>, + client: Weak, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(store: &Arc>) -> Self { + pub fn new(client: &Arc) -> Self { PersonalClient { - secret_store: Arc::downgrade(store), + client: Arc::downgrade(client), } } } impl Personal for PersonalClient { fn accounts(&self, _: Params) -> Result { - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let client = take_weak!(self.client); + let store = client.secret_store().read().unwrap(); match store.accounts() { Ok(account_list) => { Ok(Value::Array(account_list.iter() @@ -54,8 +53,8 @@ impl Personal for PersonalClient { fn new_account(&self, params: Params) -> Result { from_params::<(String, )>(params).and_then( |(pass, )| { - let store_wk = take_weak!(self.secret_store); - let mut store = store_wk.write().unwrap(); + let client = take_weak!(self.client); + let mut store = client.secret_store().write().unwrap(); match store.new_account(&pass) { Ok(address) => Ok(Value::String(format!("{:?}", address))), Err(_) => Err(Error::internal_error()) @@ -67,8 +66,8 @@ impl Personal for PersonalClient { fn unlock_account(&self, params: Params) -> Result { from_params::<(Address, String, u64)>(params).and_then( |(account, account_pass, _)|{ - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let client = take_weak!(self.client); + let store = client.secret_store().read().unwrap(); match store.unlock_account(&account, &account_pass) { Ok(_) => Ok(Value::Bool(true)), Err(_) => Ok(Value::Bool(false)), diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index f09f24e4d..44809ac70 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -15,7 +15,9 @@ // along with Parity. If not, see . use rustc_serialize::hex::ToHex; -use serde::{Serialize, Serializer}; +use serde::{Serialize, Serializer, Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::common::FromHex; /// Wrapper structure around vector of bytes. #[derive(Debug)] @@ -36,7 +38,7 @@ impl Default for Bytes { } impl Serialize for Bytes { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { let mut serialized = "0x".to_owned(); serialized.push_str(self.0.to_hex().as_ref()); @@ -44,6 +46,32 @@ impl Serialize for Bytes { } } +impl Deserialize for Bytes { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(BytesVisitor) + } +} + +struct BytesVisitor; + +impl Visitor for BytesVisitor { + type Value = Bytes; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + if value.len() >= 2 && &value[0..2] == "0x" { + Ok(Bytes::new(FromHex::from_hex(&value[2..]).unwrap_or_else(|_| vec![]))) + } else { + Err(Error::custom("invalid hex")) + } + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + + #[cfg(test)] mod tests { use super::*; diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 34c1f1cff..2b2390ecb 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -33,3 +33,5 @@ pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; +pub use self::transaction::TransactionRequest; + diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 232cf0bf3..7d40d8a49 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -17,6 +17,7 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; +use serde::{Deserializer, Error}; #[derive(Debug, Default, Serialize)] pub struct Transaction { @@ -37,6 +38,18 @@ pub struct Transaction { pub input: Bytes } +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct TransactionRequest { + pub from: Address, + pub to: Option
, + #[serde(rename="gasPrice")] + pub gas_price: Option, + pub gas: Option, + pub value: Option, + pub data: Bytes, + pub nonce: Option, +} + impl From for Transaction { fn from(t: LocalizedTransaction) -> Transaction { Transaction { From 3fa1776ecf43cb639c5ce688e85a5de1dc17c0f1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 4 Mar 2016 19:11:44 +0100 Subject: [PATCH 358/753] Fixed sync stalling on a new block arriving while body request is pending --- sync/src/chain.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index fd690e790..0b985f217 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -475,7 +475,7 @@ impl ChainSync { peer.latest_number = Some(header.number()); } // TODO: Decompose block and add to self.headers and self.bodies instead - if header.number == From::from(self.current_base_block() + 1) { + if header.number <= From::from(self.current_base_block() + 1) { match io.chain().import_block(block_rlp.as_raw().to_vec()) { Err(Error::Import(ImportError::AlreadyInChain)) => { trace!(target: "sync", "New block already in chain {:?}", h); @@ -484,7 +484,10 @@ impl ChainSync { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { - self.last_imported_block = Some(header.number); + if self.current_base_block() < header.number { + self.last_imported_block = Some(header.number); + self.remove_downloaded_blocks(header.number); + } trace!(target: "sync", "New block queued {:?}", h); }, Err(Error::Block(BlockError::UnknownParent(p))) => { From 8ff49c06dda93f241e46b99e93e9a954bec79e95 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 21:49:57 +0300 Subject: [PATCH 359/753] somehow that was not set to the right path --- sync/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 2ce65ca77..f10a772e3 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Ethcore Date: Fri, 4 Mar 2016 20:19:36 +0100 Subject: [PATCH 360/753] JournalDB can now operate in "archive" mode. --- util/src/journaldb.rs | 96 +++++++++++++++++++++++++++++++------------ util/src/overlaydb.rs | 2 +- 2 files changed, 70 insertions(+), 28 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 5e6ca47c2..cb49134ee 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -25,7 +25,10 @@ use kvdb::{Database, DBTransaction, DatabaseConfig}; use std::env; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay -/// and latent-removal semantics. +/// and, possibly, latent-removal semantics. +/// +/// If `counters` is `None`, then it behaves exactly like OverlayDB. If not it behaves +/// differently: /// /// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect @@ -34,7 +37,7 @@ use std::env; pub struct JournalDB { overlay: MemoryDB, backing: Arc, - counters: Arc>>, + counters: Option>>>, } impl Clone for JournalDB { @@ -48,10 +51,11 @@ impl Clone for JournalDB { } // all keys must be at least 12 bytes -const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; -const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; -const DB_VERSION: u32 = 3; +const DB_VERSION : u32 = 3; +const DB_VERSION_NO_JOURNAL : u32 = 3 + 256; const PADDING : [u8; 10] = [ 0u8; 10 ]; @@ -59,25 +63,38 @@ impl JournalDB { /// Create a new instance from file pub fn new(path: &str) -> JournalDB { + Self::from_prefs(path, true) + } + + /// Create a new instance from file + pub fn from_prefs(path: &str, prefer_journal: bool) -> JournalDB { let opts = DatabaseConfig { prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix }; let backing = Database::open(&opts, path).unwrap_or_else(|e| { panic!("Error opening state db: {}", e); }); + let with_journal; if !backing.is_empty() { match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { - Ok(Some(DB_VERSION)) => {}, + Ok(Some(DB_VERSION)) => { with_journal = true; }, + Ok(Some(DB_VERSION_NO_JOURNAL)) => { with_journal = false; }, v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) } } else { - backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + backing.put(&VERSION_KEY, &encode(&(if prefer_journal { DB_VERSION } else { DB_VERSION_NO_JOURNAL }))).expect("Error writing version to database"); + with_journal = prefer_journal; } - let counters = JournalDB::read_counters(&backing); + + let counters = if with_journal { + Some(Arc::new(RwLock::new(JournalDB::read_counters(&backing)))) + } else { + None + }; JournalDB { overlay: MemoryDB::new(), backing: Arc::new(backing), - counters: Arc::new(RwLock::new(counters)), + counters: counters, } } @@ -94,9 +111,48 @@ impl JournalDB { self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() } + /// Commit all recent insert operations. + pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + let have_counters = self.counters.is_some(); + if have_counters { + self.commit_with_counters(now, id, end) + } else { + self.commit_without_counters() + } + } + + /// Drain the overlay and place it into a batch for the DB. + fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> (usize, usize) { + let mut ret = 0usize; + let mut deletes = 0usize; + for i in overlay.drain().into_iter() { + let (key, (value, rc)) = i; + if rc > 0 { + assert!(rc == 1); + batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); + ret += 1; + } + if rc < 0 { + assert!(rc == -1); + ret += 1; + deletes += 1; + } + } + (ret, deletes) + } + + /// Just commit the overlay into the backing DB. + fn commit_without_counters(&mut self) -> Result { + let batch = DBTransaction::new(); + let (ret, _) = Self::batch_overlay_insertions(&mut self.overlay, &batch); + try!(self.backing.write(batch)); + Ok(ret as u32) + + } + /// Commit all recent insert operations and historical removals from the old era /// to the backing database. - pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + fn commit_with_counters(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] @@ -122,8 +178,8 @@ impl JournalDB { // record new commit's details. debug!("commit: #{} ({}), end era: {:?}", now, id, end); + let mut counters = self.counters.as_ref().unwrap().write().unwrap(); let batch = DBTransaction::new(); - let mut counters = self.counters.write().unwrap(); { let mut index = 0usize; let mut last; @@ -196,25 +252,11 @@ impl JournalDB { } // Commit overlay insertions - let mut ret = 0u32; - let mut deletes = 0usize; - for i in self.overlay.drain().into_iter() { - let (key, (value, rc)) = i; - if rc > 0 { - assert!(rc == 1); - batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); - ret += 1; - } - if rc < 0 { - assert!(rc == -1); - ret += 1; - deletes += 1; - } - } + let (ret, deletes) = Self::batch_overlay_insertions(&mut self.overlay, &batch); try!(self.backing.write(batch)); debug!("commit: Deleted {} nodes", deletes); - Ok(ret) + Ok(ret as u32) } diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index f4ed2d5d6..3c80f4148 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -146,7 +146,7 @@ impl OverlayDB { }) } - /// Get the refs and value of the given key. + /// Put the refs and value of the given key, possibly deleting it from the db. fn put_payload(&self, key: &H256, payload: (Bytes, u32)) -> bool { if payload.1 > 0 { let mut s = RlpStream::new_list(2); From bbbaffbc531571894b34f5c5a0de1e7eda453c60 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Mar 2016 21:06:28 +0100 Subject: [PATCH 361/753] "--archive" option for disabling the journal DB Fixes #579 --- ethcore/src/blockchain/blockchain.rs | 3 +++ ethcore/src/client.rs | 5 +++-- parity/main.rs | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index f412a8240..e79f1668c 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -40,6 +40,8 @@ pub struct BlockChainConfig { pub pref_cache_size: usize, /// Maximum cache size in bytes. pub max_cache_size: usize, + /// Prefer journal rather than archive. + pub prefer_journal: bool, } impl Default for BlockChainConfig { @@ -47,6 +49,7 @@ impl Default for BlockChainConfig { BlockChainConfig { pref_cache_size: 1 << 14, max_cache_size: 1 << 20, + prefer_journal: false, } } } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 422f1eaa2..87f2c9e96 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -212,7 +212,8 @@ impl Client { let mut dir = path.to_path_buf(); dir.push(H64::from(spec.genesis_header().hash()).hex()); //TODO: sec/fat: pruned/full versioning - dir.push(format!("v{}-sec-pruned", CLIENT_DB_VER_STR)); + dir.push(format!("v{}-sec-pruned-{}", CLIENT_DB_VER_STR, if config.blockchain.prefer_journal { "journal" } else { "archive" })); + let pj = config.blockchain.prefer_journal; let path = dir.as_path(); let gb = spec.genesis_block(); let chain = Arc::new(RwLock::new(BlockChain::new(config.blockchain, &gb, path))); @@ -220,7 +221,7 @@ impl Client { state_path.push("state"); let engine = Arc::new(try!(spec.to_engine())); - let mut state_db = JournalDB::new(state_path.to_str().unwrap()); + let mut state_db = JournalDB::from_prefs(state_path.to_str().unwrap(), pj); if state_db.is_empty() && engine.spec().ensure_db_good(&mut state_db) { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); } diff --git a/parity/main.rs b/parity/main.rs index b991f36cd..f1a11229f 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -65,6 +65,7 @@ Usage: Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file or frontier, mainnet, morden, or testnet [default: frontier]. + --archive Client should not prune the state/storage trie. -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] @@ -102,6 +103,7 @@ struct Args { flag_chain: String, flag_db_path: String, flag_keys_path: String, + flag_archive: bool, flag_no_bootstrap: bool, flag_listen_address: String, flag_public_address: Option, @@ -311,6 +313,7 @@ impl Configuration { let mut client_config = ClientConfig::default(); client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; + client_config.blockchain.prefer_journal = !self.args.flag_archive; client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let client = service.client().clone(); From bc018faedcffdcea398cee7848a4e2d3a64ce78a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Mar 2016 21:17:42 +0100 Subject: [PATCH 362/753] Avoid forcing a resync for the pre-existing journaldbs. --- ethcore/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 87f2c9e96..4c9e76c76 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -212,7 +212,7 @@ impl Client { let mut dir = path.to_path_buf(); dir.push(H64::from(spec.genesis_header().hash()).hex()); //TODO: sec/fat: pruned/full versioning - dir.push(format!("v{}-sec-pruned-{}", CLIENT_DB_VER_STR, if config.blockchain.prefer_journal { "journal" } else { "archive" })); + dir.push(format!("v{}-sec-pruned{}", CLIENT_DB_VER_STR, if config.blockchain.prefer_journal { "" } else { "-archive" })); let pj = config.blockchain.prefer_journal; let path = dir.as_path(); let gb = spec.genesis_block(); From f028ff1d40f95c5a5f8f0ab3cf85a9df5873b57c Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 4 Mar 2016 21:52:03 +0100 Subject: [PATCH 363/753] Use same BlockChainInfo for propagation --- sync/src/chain.rs | 56 +++++++++++++++++---------------------- sync/src/tests/helpers.rs | 2 +- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index fd690e790..cce8b12cf 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -33,7 +33,7 @@ use util::*; use std::mem::{replace}; use ethcore::views::{HeaderView}; use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockChainClient, BlockStatus, BlockId}; +use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo}; use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::block::Block; @@ -1156,9 +1156,7 @@ impl ChainSync { } /// returns peer ids that have less blocks than our chain - fn get_lagging_peers(&mut self, io: &SyncIo) -> Vec<(PeerId, BlockNumber)> { - let chain = io.chain(); - let chain_info = chain.chain_info(); + fn get_lagging_peers(&mut self, chain_info: &BlockChainInfo, io: &SyncIo) -> Vec<(PeerId, BlockNumber)> { let latest_hash = chain_info.best_block_hash; let latest_number = chain_info.best_block_number; self.peers.iter_mut().filter_map(|(&id, ref mut peer_info)| @@ -1177,9 +1175,9 @@ impl ChainSync { } /// propagates latest block to lagging peers - fn propagate_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { + fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize { let updated_peers = { - let lagging_peers = self.get_lagging_peers(io); + let lagging_peers = self.get_lagging_peers(chain_info, io); // sqrt(x)/x scaled to max u32 let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32; @@ -1196,30 +1194,30 @@ impl ChainSync { for peer_id in updated_peers { let rlp = ChainSync::create_latest_block_rlp(io.chain()); self.send_packet(io, peer_id, NEW_BLOCK_PACKET, rlp); - self.peers.get_mut(&peer_id).unwrap().latest_hash = local_best.clone(); - self.peers.get_mut(&peer_id).unwrap().latest_number = Some(best_number); + self.peers.get_mut(&peer_id).unwrap().latest_hash = chain_info.best_block_hash.clone(); + self.peers.get_mut(&peer_id).unwrap().latest_number = Some(chain_info.best_block_number); sent = sent + 1; } sent } /// propagates new known hashes to all peers - fn propagate_new_hashes(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { - let updated_peers = self.get_lagging_peers(io); + fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize { + let updated_peers = self.get_lagging_peers(chain_info, io); let mut sent = 0; - let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(local_best.clone())).unwrap()).parent_hash(); + let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(chain_info.best_block_hash.clone())).unwrap()).parent_hash(); for (peer_id, peer_number) in updated_peers { let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone(); - if best_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber { + if chain_info.best_block_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber { // If we think peer is too far behind just send one latest hash peer_best = last_parent.clone(); } - sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &local_best) { + sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &chain_info.best_block_hash) { Some(rlp) => { { let peer = self.peers.get_mut(&peer_id).unwrap(); - peer.latest_hash = local_best.clone(); - peer.latest_number = Some(best_number); + peer.latest_hash = chain_info.best_block_hash.clone(); + peer.latest_number = Some(chain_info.best_block_number); } self.send_packet(io, peer_id, NEW_BLOCK_HASHES_PACKET, rlp); 1 @@ -1239,8 +1237,8 @@ impl ChainSync { pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) { let chain = io.chain().chain_info(); if (((chain.best_block_number as i64) - (self.last_send_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let blocks = self.propagate_blocks(&chain.best_block_hash, chain.best_block_number, io); - let hashes = self.propagate_new_hashes(&chain.best_block_hash, chain.best_block_number, io); + let blocks = self.propagate_blocks(&chain, io); + let hashes = self.propagate_new_hashes(&chain, io); if blocks != 0 || hashes != 0 { trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); } @@ -1390,9 +1388,10 @@ mod tests { client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); + let chain_info = client.chain_info(); let io = TestIo::new(&mut client, &mut queue, None); - let lagging_peers = sync.get_lagging_peers(&io); + let lagging_peers = sync.get_lagging_peers(&chain_info, &io); assert_eq!(1, lagging_peers.len()) } @@ -1420,11 +1419,10 @@ mod tests { client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - let peer_count = sync.propagate_new_hashes(&best_hash, best_number, &mut io); + let peer_count = sync.propagate_new_hashes(&chain_info, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1440,11 +1438,9 @@ mod tests { client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - - let peer_count = sync.propagate_blocks(&best_hash, best_number, &mut io); + let peer_count = sync.propagate_blocks(&chain_info, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1546,11 +1542,10 @@ mod tests { client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagate_new_hashes(&best_hash, best_number, &mut io); + sync.propagate_new_hashes(&chain_info, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(&data)); @@ -1565,11 +1560,10 @@ mod tests { client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagate_blocks(&best_hash, best_number, &mut io); + sync.propagate_blocks(&chain_info, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index e9c5f0edc..e170a4a85 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -105,7 +105,7 @@ impl BlockChainClient for TestBlockChainClient { Some(U256::zero()) } - fn block_hash(&self, id: BlockId) -> Option { + fn block_hash(&self, _id: BlockId) -> Option { unimplemented!(); } From 182aec2f9463f0c96b6bec1022e5328935785248 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 4 Mar 2016 22:01:36 +0100 Subject: [PATCH 364/753] Fixed potential deadlock on startup --- util/src/network/host.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 42e8ff93d..f2cc9fe48 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -400,7 +400,8 @@ impl Host where Message: Send + Sync + Clone { // public_endpoint in host info contains local adderss at this point let listen_address = self.info.read().unwrap().public_endpoint.address.clone(); let udp_port = self.info.read().unwrap().config.udp_port.unwrap_or(listen_address.port()); - let public_endpoint = match self.info.read().unwrap().config.public_address { + let public_address = self.info.read().unwrap().config.public_address.clone(); + let public_endpoint = match public_address { None => { let public_address = select_public_address(listen_address.port()); let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; From 559e01ea84beb7ff46c67868c69d6e817ba1f986 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Mar 2016 22:54:59 +0100 Subject: [PATCH 365/753] Review remarks resolved. --- ethcore/src/client.rs | 19 +++++++++++++++---- parity/main.rs | 2 +- util/src/journaldb.rs | 9 ++++----- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 4c9e76c76..064b749a8 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -76,12 +76,24 @@ pub enum BlockStatus { } /// Client configuration. Includes configs for all sub-systems. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ClientConfig { /// Block queue configuration. pub queue: BlockQueueConfig, /// Blockchain configuration. pub blockchain: BlockChainConfig, + /// Prefer journal rather than archive. + pub prefer_journal: bool, +} + +impl Default for ClientConfig { + fn default() -> ClientConfig { + ClientConfig { + queue: Default::default(), + blockchain: Default::default(), + prefer_journal: false, + } + } } /// Information about the blockchain gathered together. @@ -212,8 +224,7 @@ impl Client { let mut dir = path.to_path_buf(); dir.push(H64::from(spec.genesis_header().hash()).hex()); //TODO: sec/fat: pruned/full versioning - dir.push(format!("v{}-sec-pruned{}", CLIENT_DB_VER_STR, if config.blockchain.prefer_journal { "" } else { "-archive" })); - let pj = config.blockchain.prefer_journal; + dir.push(format!("v{}-sec-{}", CLIENT_DB_VER_STR, if config.prefer_journal { "pruned" } else { "archive" })); let path = dir.as_path(); let gb = spec.genesis_block(); let chain = Arc::new(RwLock::new(BlockChain::new(config.blockchain, &gb, path))); @@ -221,7 +232,7 @@ impl Client { state_path.push("state"); let engine = Arc::new(try!(spec.to_engine())); - let mut state_db = JournalDB::from_prefs(state_path.to_str().unwrap(), pj); + let mut state_db = JournalDB::from_prefs(state_path.to_str().unwrap(), config.prefer_journal); if state_db.is_empty() && engine.spec().ensure_db_good(&mut state_db) { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); } diff --git a/parity/main.rs b/parity/main.rs index f1a11229f..3f4243a0a 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -313,7 +313,7 @@ impl Configuration { let mut client_config = ClientConfig::default(); client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; - client_config.blockchain.prefer_journal = !self.args.flag_archive; + client_config.prefer_journal = !self.args.flag_archive; client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let client = service.client().clone(); diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index cb49134ee..b20934397 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -147,7 +147,6 @@ impl JournalDB { let (ret, _) = Self::batch_overlay_insertions(&mut self.overlay, &batch); try!(self.backing.write(batch)); Ok(ret as u32) - } /// Commit all recent insert operations and historical removals from the old era @@ -177,7 +176,7 @@ impl JournalDB { // and the key is safe to delete. // record new commit's details. - debug!("commit: #{} ({}), end era: {:?}", now, id, end); + trace!("commit: #{} ({}), end era: {:?}", now, id, end); let mut counters = self.counters.as_ref().unwrap().write().unwrap(); let batch = DBTransaction::new(); { @@ -248,14 +247,14 @@ impl JournalDB { try!(batch.delete(&h)); deletes += 1; } - debug!("commit: Delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, deletes); + trace!("commit: Delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, deletes); } // Commit overlay insertions let (ret, deletes) = Self::batch_overlay_insertions(&mut self.overlay, &batch); try!(self.backing.write(batch)); - debug!("commit: Deleted {} nodes", deletes); + trace!("commit: Deleted {} nodes", deletes); Ok(ret as u32) } @@ -304,7 +303,7 @@ impl JournalDB { era -= 1; } } - debug!("Recovered {} counters", res.len()); + trace!("Recovered {} counters", res.len()); res } } From 96617533c8d41ac8726bd17e7de8f3f98b9178d2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Mar 2016 22:57:44 +0100 Subject: [PATCH 366/753] Remove unneeded field. --- ethcore/src/blockchain/blockchain.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index e79f1668c..f412a8240 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -40,8 +40,6 @@ pub struct BlockChainConfig { pub pref_cache_size: usize, /// Maximum cache size in bytes. pub max_cache_size: usize, - /// Prefer journal rather than archive. - pub prefer_journal: bool, } impl Default for BlockChainConfig { @@ -49,7 +47,6 @@ impl Default for BlockChainConfig { BlockChainConfig { pref_cache_size: 1 << 14, max_cache_size: 1 << 20, - prefer_journal: false, } } } From 098a6ad2cc3c33810e9036d0a29841a3124a7e18 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Mar 2016 23:09:05 +0100 Subject: [PATCH 367/753] Reset `HISTORY`. --- ethcore/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index bd8c5175b..fb46c81b1 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -207,7 +207,7 @@ pub struct Client where V: Verifier { secret_store: Arc>, } -const HISTORY: u64 = 30; +const HISTORY: u64 = 1000; const CLIENT_DB_VER_STR: &'static str = "4.0"; impl Client { From 86c34c7d10b36f39437289fa439613ae73d3f44a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Mar 2016 23:29:56 +0100 Subject: [PATCH 368/753] Remove "fix". --- ethcore/src/block.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d05ce51b9..68f647e37 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -220,8 +220,8 @@ impl<'x> OpenBlock<'x> { /// NOTE Will check chain constraints and the uncle number but will NOT check /// that the header itself is actually valid. pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> { - if self.block.base.uncles.len() > self.engine.maximum_uncle_count() { - return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len()})); + if self.block.base.uncles.len() + 1 > self.engine.maximum_uncle_count() { + return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len() + 1})); } // TODO: check number // TODO: check not a direct ancestor (use last_hashes for that) From 8f0005617171f6b7c71c9a2f10fc5e48821248b1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 4 Mar 2016 23:43:59 +0100 Subject: [PATCH 369/753] Avoid sealing unnecessarily. --- ethcore/src/client.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index fb46c81b1..845702285 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -17,6 +17,7 @@ //! Blockchain database client. use std::marker::PhantomData; +use std::sync::atomic::AtomicBool; use util::*; use util::panics::*; use blockchain::{BlockChain, BlockProvider}; @@ -200,6 +201,7 @@ pub struct Client where V: Verifier { panic_handler: Arc, // for sealing... + sealing_enabled: AtomicBool, sealing_block: Mutex>, author: RwLock
, extra_data: RwLock, @@ -251,6 +253,7 @@ impl Client where V: Verifier { report: RwLock::new(Default::default()), import_lock: Mutex::new(()), panic_handler: panic_handler, + sealing_enabled: AtomicBool::new(false), sealing_block: Mutex::new(None), author: RwLock::new(Address::new()), extra_data: RwLock::new(Vec::new()), @@ -398,7 +401,7 @@ impl Client where V: Verifier { } } - if self.chain_info().best_block_hash != original_best { + if self.chain_info().best_block_hash != original_best && self.sealing_enabled.load(atomic::Ordering::Relaxed) { self.prepare_sealing(); } @@ -481,7 +484,7 @@ impl Client where V: Verifier { self.extra_data() ); - self.chain.read().unwrap().find_uncle_headers(&h, self.engine.deref().deref().maximum_uncle_age()).unwrap().into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); + self.chain.read().unwrap().find_uncle_headers(&h, self.engine.deref().deref().maximum_uncle_age()).unwrap().into_iter().take(self.engine.deref().deref().maximum_uncle_count()).foreach(|h| { b.push_uncle(h).unwrap(); }); // TODO: push transactions. @@ -493,6 +496,8 @@ impl Client where V: Verifier { /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. pub fn sealing_block(&self) -> &Mutex> { if self.sealing_block.lock().unwrap().is_none() { + self.sealing_enabled.store(true, atomic::Ordering::Relaxed); + // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. self.prepare_sealing(); } &self.sealing_block From 2d6738fcde45f32d3b5b95e8e6b584f928864f83 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 4 Mar 2016 23:53:57 +0100 Subject: [PATCH 370/753] Additional logging and assert --- util/src/journaldb.rs | 45 ++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index b20934397..e3dd2bbfd 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -122,29 +122,29 @@ impl JournalDB { } /// Drain the overlay and place it into a batch for the DB. - fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> (usize, usize) { - let mut ret = 0usize; + fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> usize { + let mut inserts = 0usize; let mut deletes = 0usize; for i in overlay.drain().into_iter() { let (key, (value, rc)) = i; if rc > 0 { assert!(rc == 1); batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); - ret += 1; + inserts += 1; } if rc < 0 { assert!(rc == -1); - ret += 1; deletes += 1; } } - (ret, deletes) + trace!("commit: Inserted {}, Deleted {} nodes", inserts, deletes); + inserts + deletes } /// Just commit the overlay into the backing DB. fn commit_without_counters(&mut self) -> Result { let batch = DBTransaction::new(); - let (ret, _) = Self::batch_overlay_insertions(&mut self.overlay, &batch); + let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); try!(self.backing.write(batch)); Ok(ret as u32) } @@ -183,14 +183,23 @@ impl JournalDB { let mut index = 0usize; let mut last; - while try!(self.backing.get({ - let mut r = RlpStream::new_list(3); - r.append(&now); - r.append(&index); - r.append(&&PADDING[..]); - last = r.drain(); - &last - })).is_some() { + while { + let record = try!(self.backing.get({ + let mut r = RlpStream::new_list(3); + r.append(&now); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })); + match record { + Some(r) => { + assert!(&Rlp::new(&r).val_at::(0) != id); + true + }, + None => false, + } + } { index += 1; } @@ -236,6 +245,7 @@ impl JournalDB { trace!("Purging nodes inserted in non-canon: {:?}", inserts); to_remove.append(&mut inserts); } + trace!("commit: Delete journal for time #{}.{}: {}, (canon was {}): {} entries", end_era, index, rlp.val_at::(0), canon_id, to_remove.len()); try!(batch.delete(&last)); index += 1; } @@ -243,18 +253,17 @@ impl JournalDB { let canon_inserts = canon_inserts.drain(..).collect::>(); // Purge removed keys if they are not referenced and not re-inserted in the canon commit let mut deletes = 0; + trace!("Purging filtered notes: {:?}", to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)).collect::>()); for h in to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)) { try!(batch.delete(&h)); deletes += 1; } - trace!("commit: Delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, deletes); + trace!("Total nodes purged: {}", deletes); } // Commit overlay insertions - let (ret, deletes) = Self::batch_overlay_insertions(&mut self.overlay, &batch); - + let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); try!(self.backing.write(batch)); - trace!("commit: Deleted {} nodes", deletes); Ok(ret as u32) } From a4640beb2c766964d5fa905fba0d3eacfb35725c Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 5 Mar 2016 00:00:43 +0100 Subject: [PATCH 371/753] Typo --- util/src/journaldb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index e3dd2bbfd..01e53f819 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -253,7 +253,7 @@ impl JournalDB { let canon_inserts = canon_inserts.drain(..).collect::>(); // Purge removed keys if they are not referenced and not re-inserted in the canon commit let mut deletes = 0; - trace!("Purging filtered notes: {:?}", to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)).collect::>()); + trace!("Purging filtered nodes: {:?}", to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)).collect::>()); for h in to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)) { try!(batch.delete(&h)); deletes += 1; From 5ad577301420c092454c6268ca3f7a38dbb5ff44 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 5 Mar 2016 10:45:05 +0100 Subject: [PATCH 372/753] verifier improvements --- ethcore/src/client.rs | 4 ++-- ethcore/src/verification/canon_verifier.rs | 6 ++++++ ethcore/src/verification/noop_verifier.rs | 6 ++++++ ethcore/src/verification/verification.rs | 2 +- ethcore/src/verification/verifier.rs | 3 +++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c40ac2ab8..858185873 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -233,7 +233,7 @@ impl Client { impl Client where V: Verifier { /// Create a new client with given spec and DB path and custom verifier. - pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { + pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result>, Error> { let mut dir = path.to_path_buf(); dir.push(H64::from(spec.genesis_header().hash()).hex()); //TODO: sec/fat: pruned/full versioning @@ -312,7 +312,7 @@ impl Client where V: Verifier { } // Verify Block Family - let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); + let verify_family_result = V::verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); if let Err(e) = verify_family_result { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); diff --git a/ethcore/src/verification/canon_verifier.rs b/ethcore/src/verification/canon_verifier.rs index 0d9cbc6b6..30e368f1b 100644 --- a/ethcore/src/verification/canon_verifier.rs +++ b/ethcore/src/verification/canon_verifier.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use blockchain::BlockProvider; +use engine::Engine; use error::Error; use header::Header; use super::Verifier; @@ -22,6 +24,10 @@ use super::verification; pub struct CanonVerifier; impl Verifier for CanonVerifier { + fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> { + verification::verify_block_family(header, bytes, engine, bc) + } + fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> { verification::verify_block_final(expected, got) } diff --git a/ethcore/src/verification/noop_verifier.rs b/ethcore/src/verification/noop_verifier.rs index 8dfd64771..ae2a153fe 100644 --- a/ethcore/src/verification/noop_verifier.rs +++ b/ethcore/src/verification/noop_verifier.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use blockchain::BlockProvider; +use engine::Engine; use error::Error; use header::Header; use super::Verifier; @@ -21,6 +23,10 @@ use super::Verifier; pub struct NoopVerifier; impl Verifier for NoopVerifier { + fn verify_block_family(_header: &Header, _bytes: &[u8], _engine: &Engine, _bc: &BlockProvider) -> Result<(), Error> { + Ok(()) + } + fn verify_block_final(_expected: &Header, _got: &Header) -> Result<(), Error> { Ok(()) } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 761e2e8cd..ed3db3791 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -78,7 +78,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> } /// Phase 3 verification. Check block information against parent and uncles. -pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BC) -> Result<(), Error> where BC: BlockProvider { +pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> { // TODO: verify timestamp let parent = try!(bc.block_header(&header.parent_hash).ok_or_else(|| Error::from(BlockError::UnknownParent(header.parent_hash.clone())))); try!(verify_parent(&header, &parent)); diff --git a/ethcore/src/verification/verifier.rs b/ethcore/src/verification/verifier.rs index 0ffbf3bdd..cc5edce29 100644 --- a/ethcore/src/verification/verifier.rs +++ b/ethcore/src/verification/verifier.rs @@ -14,10 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use blockchain::BlockProvider; +use engine::Engine; use error::Error; use header::Header; /// Should be used to verify blocks. pub trait Verifier: Send + Sync { + fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>; fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>; } From 1d04a7b8f98614c4a883585d0b84a35a1a469853 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 13:11:54 +0300 Subject: [PATCH 373/753] changing warning to trace --- util/src/keys/store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index bfb8e6c79..625d6fd8f 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -105,7 +105,7 @@ impl SecretStore { import_path.push(".ethereum"); import_path.push("keystore"); if let Err(e) = geth_import::import_geth_keys(self, &import_path) { - warn!(target: "sstore", "Error retrieving geth keys: {:?}", e) + trace!(target: "sstore", "Geth key not imported: {:?}", e); } } From 8a13e87cbeb0905077a25092f088a54482ab2e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 11:30:09 +0100 Subject: [PATCH 374/753] Renaming BlocksWith helper to EachBlockWith --- sync/src/chain.rs | 34 +++++++++++++-------------- sync/src/tests/chain.rs | 48 +++++++++++++++++++-------------------- sync/src/tests/helpers.rs | 10 ++++---- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 983ce62c3..e8ad81a3a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -491,7 +491,7 @@ impl ChainSync { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { - if self.current_base_block() < header.number { + if self.current_base_block() < header.number { self.last_imported_block = Some(header.number); self.remove_downloaded_blocks(header.number); } @@ -1433,7 +1433,7 @@ mod tests { #[test] fn finds_lagging_peers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, BlocksWith::Uncle); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); let chain_info = client.chain_info(); @@ -1447,7 +1447,7 @@ mod tests { #[test] fn calculates_tree_for_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(15, BlocksWith::Uncle); + client.add_blocks(15, EachBlockWith::Uncle); let start = client.block_hash_delta_minus(4); let end = client.block_hash_delta_minus(2); @@ -1464,7 +1464,7 @@ mod tests { #[test] fn sends_new_hashes_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, BlocksWith::Uncle); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1483,7 +1483,7 @@ mod tests { #[test] fn sends_latest_block_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, BlocksWith::Uncle); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1501,7 +1501,7 @@ mod tests { #[test] fn handles_peer_new_block_mallformed() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, BlocksWith::Uncle); + client.add_blocks(10, EachBlockWith::Uncle); let block_data = get_dummy_block(11, client.chain_info().best_block_hash); @@ -1519,7 +1519,7 @@ mod tests { #[test] fn handles_peer_new_block() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, BlocksWith::Uncle); + client.add_blocks(10, EachBlockWith::Uncle); let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); @@ -1537,7 +1537,7 @@ mod tests { #[test] fn handles_peer_new_block_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, BlocksWith::Uncle); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1553,7 +1553,7 @@ mod tests { #[test] fn handles_peer_new_hashes() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, BlocksWith::Uncle); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1569,7 +1569,7 @@ mod tests { #[test] fn handles_peer_new_hashes_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, BlocksWith::Uncle); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1587,7 +1587,7 @@ mod tests { #[test] fn hashes_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, BlocksWith::Uncle); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1605,7 +1605,7 @@ mod tests { #[test] fn block_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, BlocksWith::Uncle); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1622,9 +1622,9 @@ mod tests { fn should_add_transactions_to_queue() { // given let mut client = TestBlockChainClient::new(); - client.add_blocks(98, BlocksWith::Uncle); - client.add_blocks(1, BlocksWith::UncleAndTransaction); - client.add_blocks(1, BlocksWith::Transaction); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let good_blocks = vec![client.block_hash_delta_minus(2)]; @@ -1648,7 +1648,7 @@ mod tests { #[test] fn returns_requested_block_headers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, BlocksWith::Uncle); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); @@ -1672,7 +1672,7 @@ mod tests { #[test] fn returns_requested_block_headers_reverse() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, BlocksWith::Uncle); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index b388f508d..58f50916e 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -24,8 +24,8 @@ use super::helpers::*; fn two_peers() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, BlocksWith::Uncle); - net.peer_mut(2).chain.add_blocks(1000, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); @@ -35,8 +35,8 @@ fn two_peers() { fn status_after_sync() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, BlocksWith::Uncle); - net.peer_mut(2).chain.add_blocks(1000, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync(); let status = net.peer(0).sync.status(); assert_eq!(status.state, SyncState::Idle); @@ -45,8 +45,8 @@ fn status_after_sync() { #[test] fn takes_few_steps() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(100, BlocksWith::Uncle); - net.peer_mut(2).chain.add_blocks(100, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(100, EachBlockWith::Uncle); let total_steps = net.sync(); assert!(total_steps < 7); } @@ -56,7 +56,7 @@ fn empty_blocks() { ::env_logger::init().ok(); let mut net = TestNet::new(3); for n in 0..200 { - let with = if n % 2 == 0 { BlocksWith::Nothing } else { BlocksWith::Uncle }; + let with = if n % 2 == 0 { EachBlockWith::Nothing } else { EachBlockWith::Uncle }; net.peer_mut(1).chain.add_blocks(5, with.clone()); net.peer_mut(2).chain.add_blocks(5, with); } @@ -69,14 +69,14 @@ fn empty_blocks() { fn forked() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(0).chain.add_blocks(300, BlocksWith::Uncle); - net.peer_mut(1).chain.add_blocks(300, BlocksWith::Uncle); - net.peer_mut(2).chain.add_blocks(300, BlocksWith::Uncle); - net.peer_mut(0).chain.add_blocks(100, BlocksWith::Nothing); //fork - net.peer_mut(1).chain.add_blocks(200, BlocksWith::Uncle); - net.peer_mut(2).chain.add_blocks(200, BlocksWith::Uncle); - net.peer_mut(1).chain.add_blocks(100, BlocksWith::Uncle); //fork between 1 and 2 - net.peer_mut(2).chain.add_blocks(10, BlocksWith::Nothing); + net.peer_mut(0).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Nothing); //fork + net.peer_mut(1).chain.add_blocks(200, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(200, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); //fork between 1 and 2 + net.peer_mut(2).chain.add_blocks(10, EachBlockWith::Nothing); // peer 1 has the best chain of 601 blocks let peer1_chain = net.peer(1).chain.numbers.read().unwrap().clone(); net.sync(); @@ -88,8 +88,8 @@ fn forked() { #[test] fn restart() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, BlocksWith::Uncle); - net.peer_mut(2).chain.add_blocks(1000, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync_steps(8); @@ -110,8 +110,8 @@ fn status_empty() { #[test] fn status_packet() { let mut net = TestNet::new(2); - net.peer_mut(0).chain.add_blocks(100, BlocksWith::Uncle); - net.peer_mut(1).chain.add_blocks(1, BlocksWith::Uncle); + net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(1, EachBlockWith::Uncle); net.start(); @@ -124,10 +124,10 @@ fn status_packet() { #[test] fn propagate_hashes() { let mut net = TestNet::new(6); - net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, BlocksWith::Uncle); + net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -150,10 +150,10 @@ fn propagate_hashes() { #[test] fn propagate_blocks() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, BlocksWith::Uncle); + net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -165,7 +165,7 @@ fn propagate_blocks() { #[test] fn restart_on_malformed_block() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.peer_mut(1).chain.corrupt_block(6); net.sync_steps(10); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index ca7776bf3..5b53ad90b 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -35,7 +35,7 @@ pub struct TestBlockChainClient { } #[derive(Clone)] -pub enum BlocksWith { +pub enum EachBlockWith { Nothing, Uncle, Transaction, @@ -52,12 +52,12 @@ impl TestBlockChainClient { last_hash: RwLock::new(H256::new()), difficulty: RwLock::new(From::from(0)), }; - client.add_blocks(1, BlocksWith::Nothing); // add genesis block + client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } - pub fn add_blocks(&mut self, count: usize, with: BlocksWith) { + pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { let len = self.numbers.read().unwrap().len(); for n in len..(len + count) { let mut header = BlockHeader::new(); @@ -65,7 +65,7 @@ impl TestBlockChainClient { header.parent_hash = self.last_hash.read().unwrap().clone(); header.number = n as BlockNumber; let uncles = match with { - BlocksWith::Uncle | BlocksWith::UncleAndTransaction => { + EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { let mut uncles = RlpStream::new_list(1); let mut uncle_header = BlockHeader::new(); uncle_header.difficulty = From::from(n); @@ -78,7 +78,7 @@ impl TestBlockChainClient { _ => RlpStream::new_list(0) }; let txs = match with { - BlocksWith::Transaction | BlocksWith::UncleAndTransaction => { + EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { let mut txs = RlpStream::new_list(1); let keypair = KeyPair::create().unwrap(); let tx = Transaction { From 1743e480e314122ceaf462b6a20b9ab420929888 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 5 Mar 2016 11:35:44 +0100 Subject: [PATCH 375/753] rust_stable --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8d2349dae..7213b8f09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: allow_failures: - rust: nightly include: + - rust: stable + env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: beta env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: nightly @@ -52,7 +54,7 @@ after_success: | ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && - [ $TRAVIS_RUST_VERSION = beta ] && + [ $TRAVIS_RUST_VERSION = stable ] && cargo doc --no-deps --verbose ${KCOV_FEATURES} ${TARGETS} && echo '' > target/doc/index.html && pip install --user ghp-import && From 9e5f8d44342ccfb93a87c46f82498a2b974c6621 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 5 Mar 2016 11:35:44 +0100 Subject: [PATCH 376/753] build on rust stable --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8d2349dae..7213b8f09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: allow_failures: - rust: nightly include: + - rust: stable + env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: beta env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: nightly @@ -52,7 +54,7 @@ after_success: | ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && - [ $TRAVIS_RUST_VERSION = beta ] && + [ $TRAVIS_RUST_VERSION = stable ] && cargo doc --no-deps --verbose ${KCOV_FEATURES} ${TARGETS} && echo '' > target/doc/index.html && pip install --user ghp-import && From b9a6a70cede04e276aaa9e1ea38ee5cef17d3133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 11:37:19 +0100 Subject: [PATCH 377/753] Renaming bad blocks as retracted --- ethcore/src/client.rs | 2 +- ethcore/src/service.rs | 2 +- sync/src/chain.rs | 11 ++++++----- sync/src/lib.rs | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index ef0356d3e..878bacce9 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -410,7 +410,7 @@ impl Client where V: Verifier { if !good_blocks.is_empty() && block_queue.queue_info().is_empty() { io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { good: good_blocks, - bad: bad_blocks, + retracted: bad_blocks, })).unwrap(); } } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 756d02407..a80adb0ba 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -30,7 +30,7 @@ pub enum SyncMessage { /// Hashes of blocks imported to blockchain good: Vec, /// Hashes of blocks not imported to blockchain - bad: Vec, + retracted: Vec, }, /// A block is ready BlockVerified, diff --git a/sync/src/chain.rs b/sync/src/chain.rs index e8ad81a3a..ddf30854a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1265,10 +1265,11 @@ impl ChainSync { } /// called when block is imported to chain, updates transactions queue - pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], bad: &[H256]) { + pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], retracted: &[H256]) { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockId::Hash(hash.clone())) + // Client should send message after commit to db and inserting to chain. .expect("Expected in-chain blocks."); let block = BlockView::new(&block); block.transactions() @@ -1277,14 +1278,14 @@ impl ChainSync { let chain = io.chain(); let good = good.par_iter().map(|h| fetch_transactions(chain, h)); - let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); + let retracted = retracted.par_iter().map(|h| fetch_transactions(chain, h)); good.for_each(|txs| { let mut transaction_queue = self.transaction_queue.lock().unwrap(); let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); }); - bad.for_each(|txs| { + retracted.for_each(|txs| { // populate sender for tx in &txs { let _sender = tx.sender(); @@ -1628,7 +1629,7 @@ mod tests { let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let good_blocks = vec![client.block_hash_delta_minus(2)]; - let bad_blocks = vec![client.block_hash_delta_minus(1)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); @@ -1637,7 +1638,7 @@ mod tests { sync.chain_new_blocks(&io, &[], &good_blocks); assert_eq!(sync.transaction_queue.lock().unwrap().status().future, 0); assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); - sync.chain_new_blocks(&io, &good_blocks, &bad_blocks); + sync.chain_new_blocks(&io, &good_blocks, &retracted_blocks); // then let status = sync.transaction_queue.lock().unwrap().status(); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 44f3f02e0..d67a09f3b 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -157,9 +157,9 @@ impl NetworkProtocolHandler for EthSync { SyncMessage::BlockVerified => { self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); }, - SyncMessage::NewChainBlocks { ref good, ref bad } => { + SyncMessage::NewChainBlocks { ref good, ref retracted } => { let sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&sync_io, good, bad); + self.sync.write().unwrap().chain_new_blocks(&sync_io, good, retracted); } } } From cfbaa2d6e99cecbd499fa7fc0eefc510e6338e84 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 14:25:46 +0300 Subject: [PATCH 378/753] fixed namespaces --- util/benches/bigint.rs | 2 +- util/benches/rlp.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index fc41ab628..575164cb6 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -28,7 +28,7 @@ extern crate ethcore_util; extern crate rand; use test::{Bencher, black_box}; -use ethcore_util::uint::*; +use ethcore_util::numbers::*; #[bench] fn u256_add(b: &mut Bencher) { diff --git a/util/benches/rlp.rs b/util/benches/rlp.rs index e94cb3635..4a983f369 100644 --- a/util/benches/rlp.rs +++ b/util/benches/rlp.rs @@ -28,7 +28,7 @@ extern crate ethcore_util; use test::Bencher; use std::str::FromStr; use ethcore_util::rlp::*; -use ethcore_util::uint::U256; +use ethcore_util::numbers::U256; #[bench] fn bench_stream_u64_value(b: &mut Bencher) { From d330f0b7b7fa5db1b5891d7c1e4e61136603fed5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 5 Mar 2016 12:53:54 +0100 Subject: [PATCH 379/753] Revert "Transaction Queue integration" --- Cargo.lock | 19 ------ ethcore/src/client.rs | 21 ++----- ethcore/src/service.rs | 2 +- sync/Cargo.toml | 1 - sync/src/chain.rs | 107 ++++++---------------------------- sync/src/lib.rs | 14 ++--- sync/src/tests/chain.rs | 51 ++++++++-------- sync/src/tests/helpers.rs | 61 +++++-------------- sync/src/transaction_queue.rs | 23 +++++--- 9 files changed, 80 insertions(+), 219 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 510e69b59..55ed996ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,14 +146,6 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "deque" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "docopt" version = "0.6.78" @@ -293,7 +285,6 @@ dependencies = [ "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -664,16 +655,6 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rayon" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "0.1.54" diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 852ba6a36..858185873 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -138,9 +138,6 @@ pub trait BlockChainClient : Sync + Send { /// Get block total difficulty. fn block_total_difficulty(&self, id: BlockId) -> Option; - /// Get address nonce. - fn nonce(&self, address: &Address) -> U256; - /// Get block hash. fn block_hash(&self, id: BlockId) -> Option; @@ -368,14 +365,18 @@ impl Client where V: Verifier { bad_blocks.insert(header.hash()); continue; } + let closed_block = self.check_and_close_block(&block); if let Err(_) = closed_block { bad_blocks.insert(header.hash()); break; } + + // Insert block + let closed_block = closed_block.unwrap(); + self.chain.write().unwrap().insert_block(&block.bytes, closed_block.block().receipts().clone()); good_blocks.push(header.hash()); - // Are we committing an era? let ancient = if header.number() >= HISTORY { let n = header.number() - HISTORY; let chain = self.chain.read().unwrap(); @@ -385,16 +386,10 @@ impl Client where V: Verifier { }; // Commit results - let closed_block = closed_block.unwrap(); - let receipts = closed_block.block().receipts().clone(); closed_block.drain() .commit(header.number(), &header.hash(), ancient) .expect("State DB commit failed."); - // And update the chain - self.chain.write().unwrap() - .insert_block(&block.bytes, receipts); - self.report.write().unwrap().accrue_block(&block); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); } @@ -413,7 +408,7 @@ impl Client where V: Verifier { if !good_blocks.is_empty() && block_queue.queue_info().is_empty() { io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { good: good_blocks, - retracted: bad_blocks, + bad: bad_blocks, })).unwrap(); } } @@ -586,10 +581,6 @@ impl BlockChainClient for Client where V: Verifier { Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) } - fn nonce(&self, address: &Address) -> U256 { - self.state().nonce(address) - } - fn block_hash(&self, id: BlockId) -> Option { let chain = self.chain.read().unwrap(); Self::block_hash(&chain, id) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index a80adb0ba..756d02407 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -30,7 +30,7 @@ pub enum SyncMessage { /// Hashes of blocks imported to blockchain good: Vec, /// Hashes of blocks not imported to blockchain - retracted: Vec, + bad: Vec, }, /// A block is ready BlockVerified, diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 0097cd47e..f10a772e3 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -17,7 +17,6 @@ time = "0.1.34" rand = "0.3.13" heapsize = "0.3" rustc-serialize = "0.3" -rayon = "0.3.1" [features] default = [] diff --git a/sync/src/chain.rs b/sync/src/chain.rs index ddf30854a..530cfa424 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -30,17 +30,14 @@ /// use util::*; -use rayon::prelude::*; use std::mem::{replace}; -use ethcore::views::{HeaderView, BlockView}; +use ethcore::views::{HeaderView}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo}; use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::block::Block; -use ethcore::transaction::SignedTransaction; use io::SyncIo; -use transaction_queue::TransactionQueue; use time; use super::SyncConfig; @@ -212,8 +209,6 @@ pub struct ChainSync { max_download_ahead_blocks: usize, /// Network ID network_id: U256, - /// Transactions Queue - transaction_queue: Mutex, } type RlpResponseResult = Result, PacketDecodeError>; @@ -239,7 +234,6 @@ impl ChainSync { last_send_block_number: 0, max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, - transaction_queue: Mutex::new(TransactionQueue::new()), } } @@ -298,7 +292,6 @@ impl ChainSync { self.starting_block = 0; self.highest_block = None; self.have_common_block = false; - self.transaction_queue.lock().unwrap().clear(); self.starting_block = io.chain().chain_info().best_block_number; self.state = SyncState::NotSynced; } @@ -491,7 +484,7 @@ impl ChainSync { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { - if self.current_base_block() < header.number { + if self.current_base_block() < header.number { self.last_imported_block = Some(header.number); self.remove_downloaded_blocks(header.number); } @@ -928,16 +921,8 @@ impl ChainSync { } } /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { - let chain = io.chain(); - let item_count = r.item_count(); - trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count); - let fetch_latest_nonce = |a : &Address| chain.nonce(a); - for i in 0..item_count { - let tx: SignedTransaction = try!(r.val_at(i)); - self.transaction_queue.lock().unwrap().add(tx, &fetch_latest_nonce); - } - Ok(()) + fn on_peer_transactions(&mut self, _io: &mut SyncIo, _peer_id: PeerId, _r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + Ok(()) } /// Send Status message @@ -1263,37 +1248,6 @@ impl ChainSync { } self.last_send_block_number = chain.best_block_number; } - - /// called when block is imported to chain, updates transactions queue - pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], retracted: &[H256]) { - fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { - let block = chain - .block(BlockId::Hash(hash.clone())) - // Client should send message after commit to db and inserting to chain. - .expect("Expected in-chain blocks."); - let block = BlockView::new(&block); - block.transactions() - } - - - let chain = io.chain(); - let good = good.par_iter().map(|h| fetch_transactions(chain, h)); - let retracted = retracted.par_iter().map(|h| fetch_transactions(chain, h)); - - good.for_each(|txs| { - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); - transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); - }); - retracted.for_each(|txs| { - // populate sender - for tx in &txs { - let _sender = tx.sender(); - } - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(txs, |a| chain.nonce(a)); - }); - } } #[cfg(test)] @@ -1434,7 +1388,7 @@ mod tests { #[test] fn finds_lagging_peers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); + client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); let chain_info = client.chain_info(); @@ -1448,7 +1402,7 @@ mod tests { #[test] fn calculates_tree_for_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(15, EachBlockWith::Uncle); + client.add_blocks(15, false); let start = client.block_hash_delta_minus(4); let end = client.block_hash_delta_minus(2); @@ -1465,7 +1419,7 @@ mod tests { #[test] fn sends_new_hashes_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); + client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1484,7 +1438,7 @@ mod tests { #[test] fn sends_latest_block_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); + client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1502,7 +1456,7 @@ mod tests { #[test] fn handles_peer_new_block_mallformed() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); + client.add_blocks(10, false); let block_data = get_dummy_block(11, client.chain_info().best_block_hash); @@ -1520,7 +1474,7 @@ mod tests { #[test] fn handles_peer_new_block() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); + client.add_blocks(10, false); let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); @@ -1538,7 +1492,7 @@ mod tests { #[test] fn handles_peer_new_block_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); + client.add_blocks(10, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1554,7 +1508,7 @@ mod tests { #[test] fn handles_peer_new_hashes() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); + client.add_blocks(10, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1570,7 +1524,7 @@ mod tests { #[test] fn handles_peer_new_hashes_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Uncle); + client.add_blocks(10, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1588,7 +1542,7 @@ mod tests { #[test] fn hashes_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); + client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1606,7 +1560,7 @@ mod tests { #[test] fn block_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); + client.add_blocks(100, false); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1619,37 +1573,10 @@ mod tests { assert!(result.is_ok()); } - #[test] - fn should_add_transactions_to_queue() { - // given - let mut client = TestBlockChainClient::new(); - client.add_blocks(98, EachBlockWith::Uncle); - client.add_blocks(1, EachBlockWith::UncleAndTransaction); - client.add_blocks(1, EachBlockWith::Transaction); - let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - - let good_blocks = vec![client.block_hash_delta_minus(2)]; - let retracted_blocks = vec![client.block_hash_delta_minus(1)]; - - let mut queue = VecDeque::new(); - let io = TestIo::new(&mut client, &mut queue, None); - - // when - sync.chain_new_blocks(&io, &[], &good_blocks); - assert_eq!(sync.transaction_queue.lock().unwrap().status().future, 0); - assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); - sync.chain_new_blocks(&io, &good_blocks, &retracted_blocks); - - // then - let status = sync.transaction_queue.lock().unwrap().status(); - assert_eq!(status.pending, 1); - assert_eq!(status.future, 0); - } - #[test] fn returns_requested_block_headers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); + client.add_blocks(100, false); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); @@ -1673,7 +1600,7 @@ mod tests { #[test] fn returns_requested_block_headers_reverse() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, EachBlockWith::Uncle); + client.add_blocks(100, false); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index d67a09f3b..74541660d 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -54,7 +54,6 @@ extern crate ethcore; extern crate env_logger; extern crate time; extern crate rand; -extern crate rayon; #[macro_use] extern crate heapsize; @@ -71,7 +70,8 @@ use io::NetSyncIo; mod chain; mod io; mod range_collection; -mod transaction_queue; +// TODO [todr] Made public to suppress dead code warnings +pub mod transaction_queue; #[cfg(test)] mod tests; @@ -153,14 +153,8 @@ impl NetworkProtocolHandler for EthSync { } fn message(&self, io: &NetworkContext, message: &SyncMessage) { - match *message { - SyncMessage::BlockVerified => { - self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); - }, - SyncMessage::NewChainBlocks { ref good, ref retracted } => { - let sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&sync_io, good, retracted); - } + if let SyncMessage::BlockVerified = *message { + self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); } } } diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 58f50916e..b01c894a0 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -24,8 +24,8 @@ use super::helpers::*; fn two_peers() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); - net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(1000, false); + net.peer_mut(2).chain.add_blocks(1000, false); net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); @@ -35,8 +35,8 @@ fn two_peers() { fn status_after_sync() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); - net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(1000, false); + net.peer_mut(2).chain.add_blocks(1000, false); net.sync(); let status = net.peer(0).sync.status(); assert_eq!(status.state, SyncState::Idle); @@ -45,8 +45,8 @@ fn status_after_sync() { #[test] fn takes_few_steps() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); - net.peer_mut(2).chain.add_blocks(100, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(100, false); + net.peer_mut(2).chain.add_blocks(100, false); let total_steps = net.sync(); assert!(total_steps < 7); } @@ -56,9 +56,8 @@ fn empty_blocks() { ::env_logger::init().ok(); let mut net = TestNet::new(3); for n in 0..200 { - let with = if n % 2 == 0 { EachBlockWith::Nothing } else { EachBlockWith::Uncle }; - net.peer_mut(1).chain.add_blocks(5, with.clone()); - net.peer_mut(2).chain.add_blocks(5, with); + net.peer_mut(1).chain.add_blocks(5, n % 2 == 0); + net.peer_mut(2).chain.add_blocks(5, n % 2 == 0); } net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); @@ -69,14 +68,14 @@ fn empty_blocks() { fn forked() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(0).chain.add_blocks(300, EachBlockWith::Uncle); - net.peer_mut(1).chain.add_blocks(300, EachBlockWith::Uncle); - net.peer_mut(2).chain.add_blocks(300, EachBlockWith::Uncle); - net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Nothing); //fork - net.peer_mut(1).chain.add_blocks(200, EachBlockWith::Uncle); - net.peer_mut(2).chain.add_blocks(200, EachBlockWith::Uncle); - net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); //fork between 1 and 2 - net.peer_mut(2).chain.add_blocks(10, EachBlockWith::Nothing); + net.peer_mut(0).chain.add_blocks(300, false); + net.peer_mut(1).chain.add_blocks(300, false); + net.peer_mut(2).chain.add_blocks(300, false); + net.peer_mut(0).chain.add_blocks(100, true); //fork + net.peer_mut(1).chain.add_blocks(200, false); + net.peer_mut(2).chain.add_blocks(200, false); + net.peer_mut(1).chain.add_blocks(100, false); //fork between 1 and 2 + net.peer_mut(2).chain.add_blocks(10, true); // peer 1 has the best chain of 601 blocks let peer1_chain = net.peer(1).chain.numbers.read().unwrap().clone(); net.sync(); @@ -88,8 +87,8 @@ fn forked() { #[test] fn restart() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); - net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(1000, false); + net.peer_mut(2).chain.add_blocks(1000, false); net.sync_steps(8); @@ -110,8 +109,8 @@ fn status_empty() { #[test] fn status_packet() { let mut net = TestNet::new(2); - net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Uncle); - net.peer_mut(1).chain.add_blocks(1, EachBlockWith::Uncle); + net.peer_mut(0).chain.add_blocks(100, false); + net.peer_mut(1).chain.add_blocks(1, false); net.start(); @@ -124,10 +123,10 @@ fn status_packet() { #[test] fn propagate_hashes() { let mut net = TestNet::new(6); - net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(10, false); net.sync(); - net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); + net.peer_mut(0).chain.add_blocks(10, false); net.sync(); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -150,10 +149,10 @@ fn propagate_hashes() { #[test] fn propagate_blocks() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(10, false); net.sync(); - net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); + net.peer_mut(0).chain.add_blocks(10, false); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -165,7 +164,7 @@ fn propagate_blocks() { #[test] fn restart_on_malformed_block() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(10, false); net.peer_mut(1).chain.corrupt_block(6); net.sync_steps(10); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 5b53ad90b..e170a4a85 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -22,7 +22,7 @@ use io::SyncIo; use chain::ChainSync; use ::SyncConfig; use ethcore::receipt::Receipt; -use ethcore::transaction::{LocalizedTransaction, Transaction, Action}; +use ethcore::transaction::LocalizedTransaction; use ethcore::filter::Filter; use ethcore::log_entry::LocalizedLogEntry; @@ -34,14 +34,6 @@ pub struct TestBlockChainClient { pub difficulty: RwLock, } -#[derive(Clone)] -pub enum EachBlockWith { - Nothing, - Uncle, - Transaction, - UncleAndTransaction -} - impl TestBlockChainClient { pub fn new() -> TestBlockChainClient { @@ -52,53 +44,30 @@ impl TestBlockChainClient { last_hash: RwLock::new(H256::new()), difficulty: RwLock::new(From::from(0)), }; - client.add_blocks(1, EachBlockWith::Nothing); // add genesis block + client.add_blocks(1, true); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } - pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { + pub fn add_blocks(&mut self, count: usize, empty: bool) { let len = self.numbers.read().unwrap().len(); for n in len..(len + count) { let mut header = BlockHeader::new(); header.difficulty = From::from(n); header.parent_hash = self.last_hash.read().unwrap().clone(); header.number = n as BlockNumber; - let uncles = match with { - EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { - let mut uncles = RlpStream::new_list(1); - let mut uncle_header = BlockHeader::new(); - uncle_header.difficulty = From::from(n); - uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); - uncle_header.number = n as BlockNumber; - uncles.append(&uncle_header); - header.uncles_hash = uncles.as_raw().sha3(); - uncles - }, - _ => RlpStream::new_list(0) - }; - let txs = match with { - EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { - let mut txs = RlpStream::new_list(1); - let keypair = KeyPair::create().unwrap(); - let tx = Transaction { - action: Action::Create, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: U256::from(100_000), - gas_price: U256::one(), - nonce: U256::zero() - }; - let signed_tx = tx.sign(&keypair.secret()); - txs.append(&signed_tx); - txs.out() - }, - _ => rlp::NULL_RLP.to_vec() - }; - + let mut uncles = RlpStream::new_list(if empty {0} else {1}); + if !empty { + let mut uncle_header = BlockHeader::new(); + uncle_header.difficulty = From::from(n); + uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); + uncle_header.number = n as BlockNumber; + uncles.append(&uncle_header); + header.uncles_hash = uncles.as_raw().sha3(); + } let mut rlp = RlpStream::new_list(3); rlp.append(&header); - rlp.append_raw(&txs, 1); + rlp.append_raw(&rlp::NULL_RLP, 1); rlp.append_raw(uncles.as_raw(), 1); self.import_block(rlp.as_raw().to_vec()).unwrap(); } @@ -140,10 +109,6 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn nonce(&self, _address: &Address) -> U256 { - U256::zero() - } - fn code(&self, _address: &Address) -> Option { unimplemented!(); } diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 83665dfda..4f5622a2f 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -219,19 +219,19 @@ impl TransactionQueue { /// Removes all transactions identified by hashes given in slice /// /// If gap is introduced marks subsequent transactions as future - pub fn remove_all(&mut self, transaction_hashes: &[H256], fetch_nonce: T) + pub fn remove_all(&mut self, txs: &[H256], fetch_nonce: T) where T: Fn(&Address) -> U256 { - for hash in transaction_hashes { - self.remove(&hash, &fetch_nonce); + for tx in txs { + self.remove(&tx, &fetch_nonce); } } /// Removes transaction identified by hashes from queue. /// /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &T) + pub fn remove(&mut self, hash: &H256, fetch_nonce: &T) where T: Fn(&Address) -> U256 { - let transaction = self.by_hash.remove(transaction_hash); + let transaction = self.by_hash.remove(hash); if transaction.is_none() { // We don't know this transaction return; @@ -240,6 +240,7 @@ impl TransactionQueue { let sender = transaction.sender(); let nonce = transaction.nonce(); + println!("Removing tx: {:?}", transaction.transaction); // Remove from future self.future.drop(&sender, &nonce); @@ -265,6 +266,7 @@ impl TransactionQueue { // Goes to future or is removed let order = self.current.drop(&sender, &k).unwrap(); if k >= current_nonce { + println!("Moving to future: {:?}", order); self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); } else { self.by_hash.remove(&order.hash); @@ -274,7 +276,7 @@ impl TransactionQueue { // And now lets check if there is some chain of transactions in future // that should be placed in current - if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce, current_nonce) { + if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce - U256::one(), current_nonce) { self.last_nonces.insert(sender, new_current_top); } } @@ -297,7 +299,9 @@ impl TransactionQueue { self.last_nonces.clear(); } - fn move_future_txs(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) -> Option { + fn move_future_txs(&mut self, address: Address, current_nonce: U256, first_nonce: U256) -> Option { + println!("Moving from future for: {:?} base: {:?}", current_nonce, first_nonce); + let mut current_nonce = current_nonce + U256::one(); { let by_nonce = self.future.by_address.row_mut(&address); if let None = by_nonce { @@ -308,6 +312,7 @@ impl TransactionQueue { // remove also from priority and hash self.future.by_priority.remove(&order); // Put to current + println!("Moved: {:?}", order); let order = order.update_height(current_nonce.clone(), first_nonce); self.current.insert(address.clone(), current_nonce, order); current_nonce = current_nonce + U256::one(); @@ -328,6 +333,7 @@ impl TransactionQueue { .cloned() .map_or_else(|| fetch_nonce(&address), |n| n + U256::one()); + println!("Expected next: {:?}, got: {:?}", next_nonce, nonce); // Check height if nonce > next_nonce { let order = TransactionOrder::for_transaction(&tx, next_nonce); @@ -339,7 +345,6 @@ impl TransactionQueue { return; } else if next_nonce > nonce { // Droping transaction - trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); return; } @@ -351,7 +356,7 @@ impl TransactionQueue { // Insert to current self.current.insert(address.clone(), nonce, order); // But maybe there are some more items waiting in future? - let new_last_nonce = self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); + let new_last_nonce = self.move_future_txs(address.clone(), nonce, base_nonce); self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); // Enforce limit self.current.enforce_limit(&self.by_hash); From 0109e5e9d4fa1110b59d907b32a158cd3b3d5762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 13:03:34 +0100 Subject: [PATCH 380/753] Removing memory leak when transactions are dropped from set --- sync/src/transaction_queue.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 83665dfda..7f9f21638 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -113,22 +113,24 @@ impl TransactionSet { self.by_address.insert(sender, nonce, order); } - fn enforce_limit(&mut self, by_hash: &HashMap) { + fn enforce_limit(&mut self, by_hash: &mut HashMap) { let len = self.by_priority.len(); if len <= self.limit { return; } - let to_drop : Vec<&VerifiedTransaction> = { + let to_drop : Vec<(Address, U256)> = { self.by_priority .iter() .skip(self.limit) .map(|order| by_hash.get(&order.hash).expect("Inconsistency in queue detected.")) + .map(|tx| (tx.sender(), tx.nonce())) .collect() }; - for tx in to_drop { - self.drop(&tx.sender(), &tx.nonce()); + for (sender, nonce) in to_drop { + let order = self.drop(&sender, &nonce).expect("Droping transaction failed."); + by_hash.remove(&order.hash).expect("Inconsistency in queue."); } } @@ -270,7 +272,7 @@ impl TransactionQueue { self.by_hash.remove(&order.hash); } } - self.future.enforce_limit(&self.by_hash); + self.future.enforce_limit(&mut self.by_hash); // And now lets check if there is some chain of transactions in future // that should be placed in current @@ -335,7 +337,7 @@ impl TransactionQueue { self.by_hash.insert(tx.hash(), tx); // We have a gap - put to future self.future.insert(address, nonce, order); - self.future.enforce_limit(&self.by_hash); + self.future.enforce_limit(&mut self.by_hash); return; } else if next_nonce > nonce { // Droping transaction @@ -354,7 +356,7 @@ impl TransactionQueue { let new_last_nonce = self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); // Enforce limit - self.current.enforce_limit(&self.by_hash); + self.current.enforce_limit(&mut self.by_hash); } } @@ -413,7 +415,7 @@ mod test { let (tx1, tx2) = new_txs(U256::from(1)); let tx1 = VerifiedTransaction::new(tx1); let tx2 = VerifiedTransaction::new(tx2); - let by_hash = { + let mut by_hash = { let mut x = HashMap::new(); let tx1 = VerifiedTransaction::new(tx1.transaction.clone()); let tx2 = VerifiedTransaction::new(tx2.transaction.clone()); @@ -430,9 +432,10 @@ mod test { assert_eq!(set.by_address.len(), 2); // when - set.enforce_limit(&by_hash); + set.enforce_limit(&mut by_hash); // then + assert_eq!(by_hash.len(), 1); assert_eq!(set.by_priority.len(), 1); assert_eq!(set.by_address.len(), 1); assert_eq!(set.by_priority.iter().next().unwrap().clone(), order1); From 78a39d3ac9b360d59c7acb430182e3fe35c0e096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 14:34:15 +0100 Subject: [PATCH 381/753] Avoid importing same transaction twice (especially with different nonce_height) --- sync/src/transaction_queue.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 7f9f21638..51ff211f6 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -129,7 +129,7 @@ impl TransactionSet { }; for (sender, nonce) in to_drop { - let order = self.drop(&sender, &nonce).expect("Droping transaction failed."); + let order = self.drop(&sender, &nonce).expect("Dropping transaction failed."); by_hash.remove(&order.hash).expect("Inconsistency in queue."); } } @@ -322,6 +322,12 @@ impl TransactionQueue { fn import_tx(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) where T: Fn(&Address) -> U256 { + + if self.by_hash.get(&tx.hash()).is_some() { + // Transaction is already imported. + return; + } + let nonce = tx.nonce(); let address = tx.sender(); @@ -355,7 +361,6 @@ impl TransactionQueue { // But maybe there are some more items waiting in future? let new_last_nonce = self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); - // Enforce limit self.current.enforce_limit(&mut self.by_hash); } } @@ -636,7 +641,26 @@ mod test { } #[test] - fn should_accept_same_transaction_twice() { + fn should_not_insert_same_transaction_twice() { + // given + let nonce = |a: &Address| default_nonce(a) + U256::one(); + let mut txq = TransactionQueue::new(); + let (_tx1, tx2) = new_txs(U256::from(1)); + txq.add(tx2.clone(), &default_nonce); + assert_eq!(txq.status().future, 1); + assert_eq!(txq.status().pending, 0); + + // when + txq.add(tx2.clone(), &nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 1); + assert_eq!(stats.pending, 0); + } + + #[test] + fn should_accept_same_transaction_twice_if_removed() { // given let mut txq = TransactionQueue::new(); let (tx1, tx2) = new_txs(U256::from(1)); From 1aaae7b55333625c572fc77cc722ea98c2517825 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 16:42:02 +0300 Subject: [PATCH 382/753] [ci skip] codegen bug --- rpc/src/v1/types/transaction.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 7d40d8a49..c24bcd08f 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -18,6 +18,8 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; use serde::{Deserializer, Error}; +use ethcore; +use util; #[derive(Debug, Default, Serialize)] pub struct Transaction { @@ -50,6 +52,22 @@ pub struct TransactionRequest { pub nonce: Option, } +impl TransactionRequest { + fn to_eth(self) -> (ethcore::transaction::Transaction, Address) { + (ethcore::transaction::Transaction { + nonce: self.nonce.unwrap_or(U256::zero()), + action: match self.to { + None => ethcore::transaction::Action::Create, + Some(addr) => ethcore::transaction::Action::Call(addr) + }, + gas: self.gas.unwrap_or(U256::zero()), + gas_price: self.gas_price.unwrap_or(U256::zero()), + value: self.value.unwrap_or(U256::zero()), + data: { let (ref x) = self.data; x } + }, self.from) + } +} + impl From for Transaction { fn from(t: LocalizedTransaction) -> Transaction { Transaction { From 765d7179f583245a432ec1f6e7c684836c60edd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 15:43:04 +0100 Subject: [PATCH 383/753] Failing tests for transaction queue --- sync/src/transaction_queue.rs | 77 ++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 51ff211f6..503af7b16 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -129,7 +129,7 @@ impl TransactionSet { }; for (sender, nonce) in to_drop { - let order = self.drop(&sender, &nonce).expect("Dropping transaction failed."); + let order = self.drop(&sender, &nonce).expect("Dropping transaction found in priority queue failed."); by_hash.remove(&order.hash).expect("Inconsistency in queue."); } } @@ -325,6 +325,7 @@ impl TransactionQueue { if self.by_hash.get(&tx.hash()).is_some() { // Transaction is already imported. + trace!(target: "sync", "Dropping already imported transaction with hash: {:?}", tx.hash()); return; } @@ -370,6 +371,7 @@ impl TransactionQueue { mod test { extern crate rustc_serialize; use self::rustc_serialize::hex::FromHex; + use std::ops::Deref; use std::collections::{HashMap, BTreeSet}; use util::crypto::KeyPair; use util::numbers::{U256, Uint}; @@ -702,4 +704,77 @@ mod test { assert_eq!(stats.pending, 2); } + #[test] + fn should_replace_same_transaction_when_has_higher_fee() { + // given + let mut txq = TransactionQueue::new(); + let keypair = KeyPair::create().unwrap(); + let tx = new_unsigned_tx(U256::from(123)).sign(&keypair.secret()); + let tx2 = { + let mut tx2 = tx.deref().clone(); + tx2.gas_price = U256::from(200); + tx2.sign(&keypair.secret()) + }; + + // when + txq.add(tx, &default_nonce); + txq.add(tx2, &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 1); + assert_eq!(stats.future, 0); + assert_eq!(txq.top_transactions(1)[0].gas_price, U256::from(200)); + } + + #[test] + fn should_replace_same_transaction_when_importing_to_futures() { + // given + let mut txq = TransactionQueue::new(); + let keypair = KeyPair::create().unwrap(); + let tx0 = new_unsigned_tx(U256::from(123)).sign(&keypair.secret()); + let tx1 = { + let mut tx1 = tx0.deref().clone(); + tx1.nonce = U256::from(124); + tx1.sign(&keypair.secret()) + }; + let tx2 = { + let mut tx2 = tx1.deref().clone(); + tx2.gas_price = U256::from(200); + tx2.sign(&keypair.secret()) + }; + + // when + txq.add(tx1, &default_nonce); + txq.add(tx2, &default_nonce); + assert_eq!(txq.status().future, 1); + txq.add(tx0, &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 2); + assert_eq!(txq.top_transactions(2)[1].gas_price, U256::from(200)); + } + + #[test] + fn should_recalculate_height_when_removing_from_future() { + // given + let previous_nonce = |a: &Address| default_nonce(a) - U256::one(); + let mut txq = TransactionQueue::new(); + let (tx1, tx2) = new_txs(U256::one()); + txq.add(tx1.clone(), &previous_nonce); + txq.add(tx2, &previous_nonce); + assert_eq!(txq.status().future, 2); + + // when + txq.remove(&tx1.hash(), &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 1); + } + + } From 6afa1c85b7862e504ee254ffb123ef14e1607213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 16:20:41 +0100 Subject: [PATCH 384/753] Replacing transactions instead of just inserting --- sync/src/transaction_queue.rs | 42 ++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 503af7b16..e05210af2 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -108,9 +108,9 @@ struct TransactionSet { } impl TransactionSet { - fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) { + fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) -> Option { self.by_priority.insert(order.clone()); - self.by_address.insert(sender, nonce, order); + self.by_address.insert(sender, nonce, order) } fn enforce_limit(&mut self, by_hash: &mut HashMap) { @@ -332,38 +332,54 @@ impl TransactionQueue { let nonce = tx.nonce(); let address = tx.sender(); + let state_nonce = fetch_nonce(&address); let next_nonce = self.last_nonces .get(&address) .cloned() - .map_or_else(|| fetch_nonce(&address), |n| n + U256::one()); + .map_or(state_nonce, |n| n + U256::one()); // Check height if nonce > next_nonce { - let order = TransactionOrder::for_transaction(&tx, next_nonce); - // Insert to by_hash - self.by_hash.insert(tx.hash(), tx); // We have a gap - put to future - self.future.insert(address, nonce, order); + Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash); self.future.enforce_limit(&mut self.by_hash); return; - } else if next_nonce > nonce { + } else if nonce < state_nonce { // Droping transaction trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); return; } let base_nonce = fetch_nonce(&address); - let order = TransactionOrder::for_transaction(&tx, base_nonce); - // Insert to by_hash - self.by_hash.insert(tx.hash(), tx); - // Insert to current - self.current.insert(address.clone(), nonce, order); + Self::replace_transaction(tx, base_nonce.clone(), &mut self.current, &mut self.by_hash); // But maybe there are some more items waiting in future? let new_last_nonce = self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); self.current.enforce_limit(&mut self.by_hash); } + + fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, set: &mut TransactionSet, by_hash: &mut HashMap) { + let order = TransactionOrder::for_transaction(&tx, base_nonce); + let hash = tx.hash(); + let address = tx.sender(); + let nonce = tx.nonce(); + + by_hash.insert(hash.clone(), tx); + if let Some(old) = set.insert(address, nonce, order.clone()) { + // There was already transaction in queue. Let's check which one should stay + if old.cmp(&order) == Ordering::Greater { + assert!(old.nonce_height == order.nonce_height, "Both transactions should have the same height."); + // Put back old transaction since it has greater priority (higher gas_price) + set.insert(address, nonce, old); + by_hash.remove(&hash); + } else { + // Make sure we remove old transaction entirely + set.by_priority.remove(&old); + by_hash.remove(&old.hash); + } + } + } } From bb8a79f18c44575d59ce68d4a9b5c03009679585 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 18:29:01 +0300 Subject: [PATCH 385/753] finalizing --- rpc/src/v1/impls/eth.rs | 12 ++++++++---- rpc/src/v1/types/bytes.rs | 1 + rpc/src/v1/types/transaction.rs | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 16b68f90f..91ccaa05a 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -260,11 +260,15 @@ impl Eth for EthClient { let client = take_weak!(self.client); let store = client.secret_store().read().unwrap(); match store.account_secret(&transaction_request.from) { - Ok(_) => { - // todo: actually sign and push to queue transaction here - Ok(Value::Bool(true)) + Ok(secret) => { + let sync = take_weak!(self.sync); + let (transaction, _) = transaction_request.to_eth(); + let signed_transaction = transaction.sign(&secret); + let hash = signed_transaction.hash(); + sync.insert_transaction(signed_transaction); + to_value(&hash) }, - Err(_) => { Ok(Value::Bool(false ))} + Err(_) => { to_value(&U256::zero()) } } }) } diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 44809ac70..466fbebde 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -28,6 +28,7 @@ impl Bytes { pub fn new(bytes: Vec) -> Bytes { Bytes(bytes) } + pub fn to_vec(self) -> Vec { let Bytes(x) = self; x } } impl Default for Bytes { diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index c24bcd08f..17b42cfcf 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -19,7 +19,6 @@ use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; use serde::{Deserializer, Error}; use ethcore; -use util; #[derive(Debug, Default, Serialize)] pub struct Transaction { @@ -53,7 +52,8 @@ pub struct TransactionRequest { } impl TransactionRequest { - fn to_eth(self) -> (ethcore::transaction::Transaction, Address) { + /// maps transaction request to the transaction that can be signed and inserted + pub fn to_eth(self) -> (ethcore::transaction::Transaction, Address) { (ethcore::transaction::Transaction { nonce: self.nonce.unwrap_or(U256::zero()), action: match self.to { @@ -63,7 +63,7 @@ impl TransactionRequest { gas: self.gas.unwrap_or(U256::zero()), gas_price: self.gas_price.unwrap_or(U256::zero()), value: self.value.unwrap_or(U256::zero()), - data: { let (ref x) = self.data; x } + data: self.data.to_vec() }, self.from) } } From 0a7fc4af738ed597239036e5c39fca0473c61512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 16:42:34 +0100 Subject: [PATCH 386/753] Recalculating heights in future when removing transaction --- sync/src/transaction_queue.rs | 68 ++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index e05210af2..24bb772d7 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -238,26 +238,50 @@ impl TransactionQueue { // We don't know this transaction return; } + let transaction = transaction.unwrap(); let sender = transaction.sender(); let nonce = transaction.nonce(); + let current_nonce = fetch_nonce(&sender); // Remove from future - self.future.drop(&sender, &nonce); - - // Remove from current - let order = self.current.drop(&sender, &nonce); - if order.is_none() { + let order = self.future.drop(&sender, &nonce); + if order.is_some() { + self.recalculate_future_for_sender(&sender, current_nonce); + // And now lets check if there is some chain of transactions in future + // that should be placed in current + self.move_future_txs(sender.clone(), current_nonce, current_nonce); return; } - // Let's remove transactions where tx.nonce < current_nonce - // and if there are any future transactions matching current_nonce+1 - move to current - let current_nonce = fetch_nonce(&sender); - // We will either move transaction to future or remove it completely - // so there will be no transactions from this sender in current - self.last_nonces.remove(&sender); + // Remove from current + let order = self.current.drop(&sender, &nonce); + if order.is_some() { + // We will either move transaction to future or remove it completely + // so there will be no transactions from this sender in current + self.last_nonces.remove(&sender); + // This should move all current transactions to future and remove old transactions + self.move_all_to_future(&sender, current_nonce); + // And now lets check if there is some chain of transactions in future + // that should be placed in current. It should also update last_nonces. + self.move_future_txs(sender.clone(), current_nonce, current_nonce); + return; + } + } + fn recalculate_future_for_sender(&mut self, sender: &Address, current_nonce: U256) { + // We need to drain all transactions for current sender from future and reinsert them with updated height + let all_nonces_from_sender = match self.future.by_address.row(&sender) { + Some(row_map) => row_map.keys().cloned().collect::>(), + None => vec![], + }; + for k in all_nonces_from_sender { + let order = self.future.drop(&sender, &k).unwrap(); + self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); + } + } + + fn move_all_to_future(&mut self, sender: &Address, current_nonce: U256) { let all_nonces_from_sender = match self.current.by_address.row(&sender) { Some(row_map) => row_map.keys().cloned().collect::>(), None => vec![], @@ -273,14 +297,9 @@ impl TransactionQueue { } } self.future.enforce_limit(&mut self.by_hash); - - // And now lets check if there is some chain of transactions in future - // that should be placed in current - if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce, current_nonce) { - self.last_nonces.insert(sender, new_current_top); - } } + /// Returns top transactions from the queue pub fn top_transactions(&self, size: usize) -> Vec { self.current.by_priority @@ -299,11 +318,11 @@ impl TransactionQueue { self.last_nonces.clear(); } - fn move_future_txs(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) -> Option { + fn move_future_txs(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { { let by_nonce = self.future.by_address.row_mut(&address); if let None = by_nonce { - return None; + return; } let mut by_nonce = by_nonce.unwrap(); while let Some(order) = by_nonce.remove(¤t_nonce) { @@ -316,8 +335,8 @@ impl TransactionQueue { } } self.future.by_address.clear_if_empty(&address); - // Returns last inserted nonce - Some(current_nonce - U256::one()) + // Update last inserted nonce + self.last_nonces.insert(address, current_nonce - U256::one()); } fn import_tx(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) @@ -353,9 +372,9 @@ impl TransactionQueue { let base_nonce = fetch_nonce(&address); Self::replace_transaction(tx, base_nonce.clone(), &mut self.current, &mut self.by_hash); + self.last_nonces.insert(address.clone(), nonce); // But maybe there are some more items waiting in future? - let new_last_nonce = self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); - self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); + self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); self.current.enforce_limit(&mut self.by_hash); } @@ -777,6 +796,7 @@ mod test { fn should_recalculate_height_when_removing_from_future() { // given let previous_nonce = |a: &Address| default_nonce(a) - U256::one(); + let next_nonce = |a: &Address| default_nonce(a) + U256::one(); let mut txq = TransactionQueue::new(); let (tx1, tx2) = new_txs(U256::one()); txq.add(tx1.clone(), &previous_nonce); @@ -784,7 +804,7 @@ mod test { assert_eq!(txq.status().future, 2); // when - txq.remove(&tx1.hash(), &default_nonce); + txq.remove(&tx1.hash(), &next_nonce); // then let stats = txq.status(); From cc3839ae5744ab887c701c9007eda6162cddff2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 16:46:04 +0100 Subject: [PATCH 387/753] Revert "Revert "Transaction Queue integration"" This reverts commit d330f0b7b7fa5db1b5891d7c1e4e61136603fed5. Conflicts: sync/src/transaction_queue.rs --- Cargo.lock | 19 ++++++ ethcore/src/client.rs | 21 +++++-- ethcore/src/service.rs | 2 +- sync/Cargo.toml | 1 + sync/src/chain.rs | 107 ++++++++++++++++++++++++++++------ sync/src/lib.rs | 14 +++-- sync/src/tests/chain.rs | 51 ++++++++-------- sync/src/tests/helpers.rs | 61 ++++++++++++++----- sync/src/transaction_queue.rs | 17 +++--- 9 files changed, 217 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55ed996ed..510e69b59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,6 +146,14 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "deque" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "docopt" version = "0.6.78" @@ -285,6 +293,7 @@ dependencies = [ "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -655,6 +664,16 @@ dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rayon" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex" version = "0.1.54" diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 858185873..852ba6a36 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -138,6 +138,9 @@ pub trait BlockChainClient : Sync + Send { /// Get block total difficulty. fn block_total_difficulty(&self, id: BlockId) -> Option; + /// Get address nonce. + fn nonce(&self, address: &Address) -> U256; + /// Get block hash. fn block_hash(&self, id: BlockId) -> Option; @@ -365,18 +368,14 @@ impl Client where V: Verifier { bad_blocks.insert(header.hash()); continue; } - let closed_block = self.check_and_close_block(&block); if let Err(_) = closed_block { bad_blocks.insert(header.hash()); break; } - - // Insert block - let closed_block = closed_block.unwrap(); - self.chain.write().unwrap().insert_block(&block.bytes, closed_block.block().receipts().clone()); good_blocks.push(header.hash()); + // Are we committing an era? let ancient = if header.number() >= HISTORY { let n = header.number() - HISTORY; let chain = self.chain.read().unwrap(); @@ -386,10 +385,16 @@ impl Client where V: Verifier { }; // Commit results + let closed_block = closed_block.unwrap(); + let receipts = closed_block.block().receipts().clone(); closed_block.drain() .commit(header.number(), &header.hash(), ancient) .expect("State DB commit failed."); + // And update the chain + self.chain.write().unwrap() + .insert_block(&block.bytes, receipts); + self.report.write().unwrap().accrue_block(&block); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); } @@ -408,7 +413,7 @@ impl Client where V: Verifier { if !good_blocks.is_empty() && block_queue.queue_info().is_empty() { io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { good: good_blocks, - bad: bad_blocks, + retracted: bad_blocks, })).unwrap(); } } @@ -581,6 +586,10 @@ impl BlockChainClient for Client where V: Verifier { Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) } + fn nonce(&self, address: &Address) -> U256 { + self.state().nonce(address) + } + fn block_hash(&self, id: BlockId) -> Option { let chain = self.chain.read().unwrap(); Self::block_hash(&chain, id) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 756d02407..a80adb0ba 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -30,7 +30,7 @@ pub enum SyncMessage { /// Hashes of blocks imported to blockchain good: Vec, /// Hashes of blocks not imported to blockchain - bad: Vec, + retracted: Vec, }, /// A block is ready BlockVerified, diff --git a/sync/Cargo.toml b/sync/Cargo.toml index f10a772e3..0097cd47e 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -17,6 +17,7 @@ time = "0.1.34" rand = "0.3.13" heapsize = "0.3" rustc-serialize = "0.3" +rayon = "0.3.1" [features] default = [] diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 530cfa424..ddf30854a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -30,14 +30,17 @@ /// use util::*; +use rayon::prelude::*; use std::mem::{replace}; -use ethcore::views::{HeaderView}; +use ethcore::views::{HeaderView, BlockView}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo}; use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::block::Block; +use ethcore::transaction::SignedTransaction; use io::SyncIo; +use transaction_queue::TransactionQueue; use time; use super::SyncConfig; @@ -209,6 +212,8 @@ pub struct ChainSync { max_download_ahead_blocks: usize, /// Network ID network_id: U256, + /// Transactions Queue + transaction_queue: Mutex, } type RlpResponseResult = Result, PacketDecodeError>; @@ -234,6 +239,7 @@ impl ChainSync { last_send_block_number: 0, max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, + transaction_queue: Mutex::new(TransactionQueue::new()), } } @@ -292,6 +298,7 @@ impl ChainSync { self.starting_block = 0; self.highest_block = None; self.have_common_block = false; + self.transaction_queue.lock().unwrap().clear(); self.starting_block = io.chain().chain_info().best_block_number; self.state = SyncState::NotSynced; } @@ -484,7 +491,7 @@ impl ChainSync { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { - if self.current_base_block() < header.number { + if self.current_base_block() < header.number { self.last_imported_block = Some(header.number); self.remove_downloaded_blocks(header.number); } @@ -921,8 +928,16 @@ impl ChainSync { } } /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, _io: &mut SyncIo, _peer_id: PeerId, _r: &UntrustedRlp) -> Result<(), PacketDecodeError> { - Ok(()) + fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + let chain = io.chain(); + let item_count = r.item_count(); + trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count); + let fetch_latest_nonce = |a : &Address| chain.nonce(a); + for i in 0..item_count { + let tx: SignedTransaction = try!(r.val_at(i)); + self.transaction_queue.lock().unwrap().add(tx, &fetch_latest_nonce); + } + Ok(()) } /// Send Status message @@ -1248,6 +1263,37 @@ impl ChainSync { } self.last_send_block_number = chain.best_block_number; } + + /// called when block is imported to chain, updates transactions queue + pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], retracted: &[H256]) { + fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { + let block = chain + .block(BlockId::Hash(hash.clone())) + // Client should send message after commit to db and inserting to chain. + .expect("Expected in-chain blocks."); + let block = BlockView::new(&block); + block.transactions() + } + + + let chain = io.chain(); + let good = good.par_iter().map(|h| fetch_transactions(chain, h)); + let retracted = retracted.par_iter().map(|h| fetch_transactions(chain, h)); + + good.for_each(|txs| { + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); + transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); + }); + retracted.for_each(|txs| { + // populate sender + for tx in &txs { + let _sender = tx.sender(); + } + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.add_all(txs, |a| chain.nonce(a)); + }); + } } #[cfg(test)] @@ -1388,7 +1434,7 @@ mod tests { #[test] fn finds_lagging_peers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); let chain_info = client.chain_info(); @@ -1402,7 +1448,7 @@ mod tests { #[test] fn calculates_tree_for_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(15, false); + client.add_blocks(15, EachBlockWith::Uncle); let start = client.block_hash_delta_minus(4); let end = client.block_hash_delta_minus(2); @@ -1419,7 +1465,7 @@ mod tests { #[test] fn sends_new_hashes_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1438,7 +1484,7 @@ mod tests { #[test] fn sends_latest_block_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1456,7 +1502,7 @@ mod tests { #[test] fn handles_peer_new_block_mallformed() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let block_data = get_dummy_block(11, client.chain_info().best_block_hash); @@ -1474,7 +1520,7 @@ mod tests { #[test] fn handles_peer_new_block() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); @@ -1492,7 +1538,7 @@ mod tests { #[test] fn handles_peer_new_block_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1508,7 +1554,7 @@ mod tests { #[test] fn handles_peer_new_hashes() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1524,7 +1570,7 @@ mod tests { #[test] fn handles_peer_new_hashes_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1542,7 +1588,7 @@ mod tests { #[test] fn hashes_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1560,7 +1606,7 @@ mod tests { #[test] fn block_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let chain_info = client.chain_info(); @@ -1573,10 +1619,37 @@ mod tests { assert!(result.is_ok()); } + #[test] + fn should_add_transactions_to_queue() { + // given + let mut client = TestBlockChainClient::new(); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + + let mut queue = VecDeque::new(); + let io = TestIo::new(&mut client, &mut queue, None); + + // when + sync.chain_new_blocks(&io, &[], &good_blocks); + assert_eq!(sync.transaction_queue.lock().unwrap().status().future, 0); + assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); + sync.chain_new_blocks(&io, &good_blocks, &retracted_blocks); + + // then + let status = sync.transaction_queue.lock().unwrap().status(); + assert_eq!(status.pending, 1); + assert_eq!(status.future, 0); + } + #[test] fn returns_requested_block_headers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); @@ -1600,7 +1673,7 @@ mod tests { #[test] fn returns_requested_block_headers_reverse() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let io = TestIo::new(&mut client, &mut queue, None); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 74541660d..d67a09f3b 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -54,6 +54,7 @@ extern crate ethcore; extern crate env_logger; extern crate time; extern crate rand; +extern crate rayon; #[macro_use] extern crate heapsize; @@ -70,8 +71,7 @@ use io::NetSyncIo; mod chain; mod io; mod range_collection; -// TODO [todr] Made public to suppress dead code warnings -pub mod transaction_queue; +mod transaction_queue; #[cfg(test)] mod tests; @@ -153,8 +153,14 @@ impl NetworkProtocolHandler for EthSync { } fn message(&self, io: &NetworkContext, message: &SyncMessage) { - if let SyncMessage::BlockVerified = *message { - self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); + match *message { + SyncMessage::BlockVerified => { + self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); + }, + SyncMessage::NewChainBlocks { ref good, ref retracted } => { + let sync_io = NetSyncIo::new(io, self.chain.deref()); + self.sync.write().unwrap().chain_new_blocks(&sync_io, good, retracted); + } } } } diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index b01c894a0..58f50916e 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -24,8 +24,8 @@ use super::helpers::*; fn two_peers() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); @@ -35,8 +35,8 @@ fn two_peers() { fn status_after_sync() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync(); let status = net.peer(0).sync.status(); assert_eq!(status.state, SyncState::Idle); @@ -45,8 +45,8 @@ fn status_after_sync() { #[test] fn takes_few_steps() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(100, false); - net.peer_mut(2).chain.add_blocks(100, false); + net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(100, EachBlockWith::Uncle); let total_steps = net.sync(); assert!(total_steps < 7); } @@ -56,8 +56,9 @@ fn empty_blocks() { ::env_logger::init().ok(); let mut net = TestNet::new(3); for n in 0..200 { - net.peer_mut(1).chain.add_blocks(5, n % 2 == 0); - net.peer_mut(2).chain.add_blocks(5, n % 2 == 0); + let with = if n % 2 == 0 { EachBlockWith::Nothing } else { EachBlockWith::Uncle }; + net.peer_mut(1).chain.add_blocks(5, with.clone()); + net.peer_mut(2).chain.add_blocks(5, with); } net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); @@ -68,14 +69,14 @@ fn empty_blocks() { fn forked() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(0).chain.add_blocks(300, false); - net.peer_mut(1).chain.add_blocks(300, false); - net.peer_mut(2).chain.add_blocks(300, false); - net.peer_mut(0).chain.add_blocks(100, true); //fork - net.peer_mut(1).chain.add_blocks(200, false); - net.peer_mut(2).chain.add_blocks(200, false); - net.peer_mut(1).chain.add_blocks(100, false); //fork between 1 and 2 - net.peer_mut(2).chain.add_blocks(10, true); + net.peer_mut(0).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Nothing); //fork + net.peer_mut(1).chain.add_blocks(200, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(200, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); //fork between 1 and 2 + net.peer_mut(2).chain.add_blocks(10, EachBlockWith::Nothing); // peer 1 has the best chain of 601 blocks let peer1_chain = net.peer(1).chain.numbers.read().unwrap().clone(); net.sync(); @@ -87,8 +88,8 @@ fn forked() { #[test] fn restart() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync_steps(8); @@ -109,8 +110,8 @@ fn status_empty() { #[test] fn status_packet() { let mut net = TestNet::new(2); - net.peer_mut(0).chain.add_blocks(100, false); - net.peer_mut(1).chain.add_blocks(1, false); + net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(1, EachBlockWith::Uncle); net.start(); @@ -123,10 +124,10 @@ fn status_packet() { #[test] fn propagate_hashes() { let mut net = TestNet::new(6); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, false); + net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -149,10 +150,10 @@ fn propagate_hashes() { #[test] fn propagate_blocks() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, false); + net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); net.trigger_block_verified(0); //first event just sets the marker net.trigger_block_verified(0); @@ -164,7 +165,7 @@ fn propagate_blocks() { #[test] fn restart_on_malformed_block() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.peer_mut(1).chain.corrupt_block(6); net.sync_steps(10); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index e170a4a85..5b53ad90b 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -22,7 +22,7 @@ use io::SyncIo; use chain::ChainSync; use ::SyncConfig; use ethcore::receipt::Receipt; -use ethcore::transaction::LocalizedTransaction; +use ethcore::transaction::{LocalizedTransaction, Transaction, Action}; use ethcore::filter::Filter; use ethcore::log_entry::LocalizedLogEntry; @@ -34,6 +34,14 @@ pub struct TestBlockChainClient { pub difficulty: RwLock, } +#[derive(Clone)] +pub enum EachBlockWith { + Nothing, + Uncle, + Transaction, + UncleAndTransaction +} + impl TestBlockChainClient { pub fn new() -> TestBlockChainClient { @@ -44,30 +52,53 @@ impl TestBlockChainClient { last_hash: RwLock::new(H256::new()), difficulty: RwLock::new(From::from(0)), }; - client.add_blocks(1, true); // add genesis block + client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } - pub fn add_blocks(&mut self, count: usize, empty: bool) { + pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { let len = self.numbers.read().unwrap().len(); for n in len..(len + count) { let mut header = BlockHeader::new(); header.difficulty = From::from(n); header.parent_hash = self.last_hash.read().unwrap().clone(); header.number = n as BlockNumber; - let mut uncles = RlpStream::new_list(if empty {0} else {1}); - if !empty { - let mut uncle_header = BlockHeader::new(); - uncle_header.difficulty = From::from(n); - uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); - uncle_header.number = n as BlockNumber; - uncles.append(&uncle_header); - header.uncles_hash = uncles.as_raw().sha3(); - } + let uncles = match with { + EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { + let mut uncles = RlpStream::new_list(1); + let mut uncle_header = BlockHeader::new(); + uncle_header.difficulty = From::from(n); + uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); + uncle_header.number = n as BlockNumber; + uncles.append(&uncle_header); + header.uncles_hash = uncles.as_raw().sha3(); + uncles + }, + _ => RlpStream::new_list(0) + }; + let txs = match with { + EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { + let mut txs = RlpStream::new_list(1); + let keypair = KeyPair::create().unwrap(); + let tx = Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero() + }; + let signed_tx = tx.sign(&keypair.secret()); + txs.append(&signed_tx); + txs.out() + }, + _ => rlp::NULL_RLP.to_vec() + }; + let mut rlp = RlpStream::new_list(3); rlp.append(&header); - rlp.append_raw(&rlp::NULL_RLP, 1); + rlp.append_raw(&txs, 1); rlp.append_raw(uncles.as_raw(), 1); self.import_block(rlp.as_raw().to_vec()).unwrap(); } @@ -109,6 +140,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn nonce(&self, _address: &Address) -> U256 { + U256::zero() + } + fn code(&self, _address: &Address) -> Option { unimplemented!(); } diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 100435530..8b38c64ad 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -221,19 +221,19 @@ impl TransactionQueue { /// Removes all transactions identified by hashes given in slice /// /// If gap is introduced marks subsequent transactions as future - pub fn remove_all(&mut self, txs: &[H256], fetch_nonce: T) + pub fn remove_all(&mut self, transaction_hashes: &[H256], fetch_nonce: T) where T: Fn(&Address) -> U256 { - for tx in txs { - self.remove(&tx, &fetch_nonce); + for hash in transaction_hashes { + self.remove(&hash, &fetch_nonce); } } /// Removes transaction identified by hashes from queue. /// /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, hash: &H256, fetch_nonce: &T) + pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &T) where T: Fn(&Address) -> U256 { - let transaction = self.by_hash.remove(hash); + let transaction = self.by_hash.remove(transaction_hash); if transaction.is_none() { // We don't know this transaction return; @@ -244,7 +244,6 @@ impl TransactionQueue { let nonce = transaction.nonce(); let current_nonce = fetch_nonce(&sender); - println!("Removing tx: {:?}", transaction.transaction); // Remove from future let order = self.future.drop(&sender, &nonce); if order.is_some() { @@ -292,7 +291,6 @@ impl TransactionQueue { // Goes to future or is removed let order = self.current.drop(&sender, &k).unwrap(); if k >= current_nonce { - println!("Moving to future: {:?}", order); self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); } else { self.by_hash.remove(&order.hash); @@ -302,7 +300,7 @@ impl TransactionQueue { // And now lets check if there is some chain of transactions in future // that should be placed in current - if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce - U256::one(), current_nonce) { + if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce, current_nonce) { self.last_nonces.insert(sender, new_current_top); } } @@ -337,7 +335,6 @@ impl TransactionQueue { // remove also from priority and hash self.future.by_priority.remove(&order); // Put to current - println!("Moved: {:?}", order); let order = order.update_height(current_nonce.clone(), first_nonce); self.current.insert(address.clone(), current_nonce, order); current_nonce = current_nonce + U256::one(); @@ -366,7 +363,6 @@ impl TransactionQueue { .cloned() .map_or(state_nonce, |n| n + U256::one()); - println!("Expected next: {:?}, got: {:?}", next_nonce, nonce); // Check height if nonce > next_nonce { // We have a gap - put to future @@ -375,6 +371,7 @@ impl TransactionQueue { return; } else if nonce < state_nonce { // Droping transaction + trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); return; } From 8915974cf0aba8e26f27294cb3510edd600252fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 16:48:03 +0100 Subject: [PATCH 388/753] Fixing compilation --- sync/src/transaction_queue.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 8b38c64ad..24bb772d7 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -297,12 +297,6 @@ impl TransactionQueue { } } self.future.enforce_limit(&mut self.by_hash); - - // And now lets check if there is some chain of transactions in future - // that should be placed in current - if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce, current_nonce) { - self.last_nonces.insert(sender, new_current_top); - } } From ae1c1b918faea16a81d2fe582446a148fdea3c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 16:51:01 +0100 Subject: [PATCH 389/753] Fixing compilation --- sync/src/transaction_queue.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 8b38c64ad..24bb772d7 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -297,12 +297,6 @@ impl TransactionQueue { } } self.future.enforce_limit(&mut self.by_hash); - - // And now lets check if there is some chain of transactions in future - // that should be placed in current - if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce, current_nonce) { - self.last_nonces.insert(sender, new_current_top); - } } From c13afcf40485411788b6817cb324a23f9de32d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 17:06:04 +0100 Subject: [PATCH 390/753] Removing assertion and just comparing fees --- sync/src/transaction_queue.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 24bb772d7..f14d94c8c 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -387,8 +387,9 @@ impl TransactionQueue { by_hash.insert(hash.clone(), tx); if let Some(old) = set.insert(address, nonce, order.clone()) { // There was already transaction in queue. Let's check which one should stay - if old.cmp(&order) == Ordering::Greater { - assert!(old.nonce_height == order.nonce_height, "Both transactions should have the same height."); + let old_fee = old.gas_price; + let new_fee = order.gas_price; + if old_fee.cmp(&new_fee) == Ordering::Greater { // Put back old transaction since it has greater priority (higher gas_price) set.insert(address, nonce, old); by_hash.remove(&hash); From 18cbea394d53abde1780efbb1cc3ea0c8e678ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 17:14:48 +0100 Subject: [PATCH 391/753] Small renaming --- sync/src/transaction_queue.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index f14d94c8c..463607cae 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -247,10 +247,10 @@ impl TransactionQueue { // Remove from future let order = self.future.drop(&sender, &nonce); if order.is_some() { - self.recalculate_future_for_sender(&sender, current_nonce); + self.update_future(&sender, current_nonce); // And now lets check if there is some chain of transactions in future // that should be placed in current - self.move_future_txs(sender.clone(), current_nonce, current_nonce); + self.move_matching_future_to_current(sender.clone(), current_nonce, current_nonce); return; } @@ -264,12 +264,12 @@ impl TransactionQueue { self.move_all_to_future(&sender, current_nonce); // And now lets check if there is some chain of transactions in future // that should be placed in current. It should also update last_nonces. - self.move_future_txs(sender.clone(), current_nonce, current_nonce); + self.move_matching_future_to_current(sender.clone(), current_nonce, current_nonce); return; } } - fn recalculate_future_for_sender(&mut self, sender: &Address, current_nonce: U256) { + fn update_future(&mut self, sender: &Address, current_nonce: U256) { // We need to drain all transactions for current sender from future and reinsert them with updated height let all_nonces_from_sender = match self.future.by_address.row(&sender) { Some(row_map) => row_map.keys().cloned().collect::>(), @@ -318,7 +318,7 @@ impl TransactionQueue { self.last_nonces.clear(); } - fn move_future_txs(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { + fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { { let by_nonce = self.future.by_address.row_mut(&address); if let None = by_nonce { @@ -374,7 +374,7 @@ impl TransactionQueue { Self::replace_transaction(tx, base_nonce.clone(), &mut self.current, &mut self.by_hash); self.last_nonces.insert(address.clone(), nonce); // But maybe there are some more items waiting in future? - self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); + self.move_matching_future_to_current(address.clone(), nonce + U256::one(), base_nonce); self.current.enforce_limit(&mut self.by_hash); } From 4a53d62be436513d81209db0d4a88ccc0f3aef06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 17:41:35 +0100 Subject: [PATCH 392/753] Fixing inconsistency when replacing transactions in queue --- sync/src/transaction_queue.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 463607cae..b98772199 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -348,8 +348,8 @@ impl TransactionQueue { return; } - let nonce = tx.nonce(); let address = tx.sender(); + let nonce = tx.nonce(); let state_nonce = fetch_nonce(&address); let next_nonce = self.last_nonces @@ -370,7 +370,6 @@ impl TransactionQueue { } let base_nonce = fetch_nonce(&address); - Self::replace_transaction(tx, base_nonce.clone(), &mut self.current, &mut self.by_hash); self.last_nonces.insert(address.clone(), nonce); // But maybe there are some more items waiting in future? @@ -391,7 +390,9 @@ impl TransactionQueue { let new_fee = order.gas_price; if old_fee.cmp(&new_fee) == Ordering::Greater { // Put back old transaction since it has greater priority (higher gas_price) - set.insert(address, nonce, old); + set.by_address.insert(address, nonce, old); + // and remove new one + set.by_priority.remove(&order); by_hash.remove(&hash); } else { // Make sure we remove old transaction entirely From 57e6e1e1b59188cdf8d378b81c33842d5c5feaf7 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 20:15:19 +0300 Subject: [PATCH 393/753] [ci ship] redundant lines --- sync/src/transaction_queue.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index b98772199..3e0d931b5 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -813,6 +813,4 @@ mod test { assert_eq!(stats.future, 0); assert_eq!(stats.pending, 1); } - - } From e100ecbeacf6bac923f4b8e416621f98668b4830 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 23:47:28 +0300 Subject: [PATCH 394/753] exposing in lib --- sync/src/chain.rs | 4 ++++ sync/src/lib.rs | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index ddf30854a..fd1771045 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1294,6 +1294,10 @@ impl ChainSync { transaction_queue.add_all(txs, |a| chain.nonce(a)); }); } + + pub fn transaction_queue(&self) -> &Mutex { + return &self.transaction_queue; + } } #[cfg(test)] diff --git a/sync/src/lib.rs b/sync/src/lib.rs index d67a09f3b..a6480b0ad 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -128,6 +128,16 @@ impl EthSync { pub fn restart(&mut self, io: &mut NetworkContext) { self.sync.write().unwrap().restart(&mut NetSyncIo::new(io, self.chain.deref())); } + + /// Insert transaction in transaction queue + pub fn insert_transaction(&self, transaction: SignedTransaction) { + use util::numbers::*; + + let nonce_fn = |a: &Address| self.chain.state().nonce(a) + U256::one(); + let sync = self.sync.write().unwrap(); + let mut queue = sync.transaction_queue().lock().unwrap(); + queue.add(transaction, &nonce_fn); + } } impl NetworkProtocolHandler for EthSync { From ad8135668392aa733dea014231a3a56469dae5fc Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 6 Mar 2016 00:48:00 +0300 Subject: [PATCH 395/753] fix namespace --- sync/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/src/lib.rs b/sync/src/lib.rs index a6480b0ad..e352144bd 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -130,7 +130,7 @@ impl EthSync { } /// Insert transaction in transaction queue - pub fn insert_transaction(&self, transaction: SignedTransaction) { + pub fn insert_transaction(&self, transaction: ethcore::transaction::SignedTransaction) { use util::numbers::*; let nonce_fn = |a: &Address| self.chain.state().nonce(a) + U256::one(); From 003d1fd0cc1c1f815c8f0b772baefd374dab67aa Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 5 Mar 2016 23:09:51 +0100 Subject: [PATCH 396/753] Network tracing improvements --- sync/src/chain.rs | 2 +- util/src/network/connection.rs | 10 ++++---- util/src/network/handshake.rs | 14 +++++------ util/src/network/host.rs | 43 +++++++++++++++++++--------------- util/src/network/session.rs | 9 ++++--- 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 530cfa424..63640f87f 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -575,7 +575,7 @@ impl ChainSync { pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { trace!(target: "sync", "== Connected {}", peer); if let Err(e) = self.send_status(io) { - warn!(target:"sync", "Error sending status request: {:?}", e); + trace!(target:"sync", "Error sending status request: {:?}", e); io.disable_peer(peer); } } diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 55e688c91..fe65be6d1 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -190,25 +190,25 @@ impl Connection { /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { - trace!(target: "net", "connection register; token={:?}", reg); + trace!(target: "network", "connection register; token={:?}", reg); if let Err(e) = event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()) { - debug!("Failed to register {:?}, {:?}", reg, e); + trace!(target: "network", "Failed to register {:?}, {:?}", reg, e); } Ok(()) } /// Update connection registration. Should be called at the end of the IO handler. pub fn update_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { - trace!(target: "net", "connection reregister; token={:?}", reg); + trace!(target: "network", "connection reregister; token={:?}", reg); event_loop.reregister( &self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| { - debug!("Failed to reregister {:?}, {:?}", reg, e); + trace!(target: "network", "Failed to reregister {:?}, {:?}", reg, e); Ok(()) }) } /// Delete connection registration. Should be called at the end of the IO handler. pub fn deregister_socket(&self, event_loop: &mut EventLoop) -> io::Result<()> { - trace!(target: "net", "connection deregister; token={:?}", self.token); + trace!(target: "network", "connection deregister; token={:?}", self.token); event_loop.deregister(&self.socket).ok(); // ignore errors here Ok(()) } diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index cca133ba9..a72cc28ad 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -222,7 +222,7 @@ impl Handshake { /// Parse, validate and confirm auth message fn read_auth(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"net", "Received handshake auth from {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received handshake auth from {:?}", self.connection.socket.peer_addr()); if data.len() != V4_AUTH_PACKET_SIZE { debug!(target:"net", "Wrong auth packet size"); return Err(From::from(NetworkError::BadProtocol)); @@ -253,7 +253,7 @@ impl Handshake { } fn read_auth_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"net", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); self.auth_cipher.extend_from_slice(data); let auth = try!(ecies::decrypt(secret, &self.auth_cipher[0..2], &self.auth_cipher[2..])); let rlp = UntrustedRlp::new(&auth); @@ -268,7 +268,7 @@ impl Handshake { /// Parse and validate ack message fn read_ack(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); if data.len() != V4_ACK_PACKET_SIZE { debug!(target:"net", "Wrong ack packet size"); return Err(From::from(NetworkError::BadProtocol)); @@ -296,7 +296,7 @@ impl Handshake { } fn read_ack_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"net", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); self.ack_cipher.extend_from_slice(data); let ack = try!(ecies::decrypt(secret, &self.ack_cipher[0..2], &self.ack_cipher[2..])); let rlp = UntrustedRlp::new(&ack); @@ -309,7 +309,7 @@ impl Handshake { /// Sends auth message fn write_auth(&mut self, secret: &Secret, public: &Public) -> Result<(), UtilError> { - trace!(target:"net", "Sending handshake auth to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Sending handshake auth to {:?}", self.connection.socket.peer_addr()); let mut data = [0u8; /*Signature::SIZE*/ 65 + /*H256::SIZE*/ 32 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32 + 1]; //TODO: use associated constants let len = data.len(); { @@ -336,7 +336,7 @@ impl Handshake { /// Sends ack message fn write_ack(&mut self) -> Result<(), UtilError> { - trace!(target:"net", "Sending handshake ack to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Sending handshake ack to {:?}", self.connection.socket.peer_addr()); let mut data = [0u8; 1 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32]; //TODO: use associated constants let len = data.len(); { @@ -355,7 +355,7 @@ impl Handshake { /// Sends EIP8 ack message fn write_ack_eip8(&mut self) -> Result<(), UtilError> { - trace!(target:"net", "Sending EIP8 handshake ack to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Sending EIP8 handshake ack to {:?}", self.connection.socket.peer_addr()); let mut rlp = RlpStream::new_list(3); rlp.append(self.ecdhe.public()); rlp.append(&self.nonce); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index f2cc9fe48..ece24a1d1 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -170,29 +170,37 @@ pub struct NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'sta io: &'s IoContext>, protocol: ProtocolId, sessions: Arc>>, - session: Option, + session: Option, + session_id: Option, } impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'static, { /// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler. fn new(io: &'s IoContext>, protocol: ProtocolId, - session: Option, sessions: Arc>>) -> NetworkContext<'s, Message> { + session: Option, sessions: Arc>>) -> NetworkContext<'s, Message> { + let id = session.as_ref().map(|s| s.lock().unwrap().token()); NetworkContext { io: io, protocol: protocol, + session_id: id, session: session, sessions: sessions, } } + fn resolve_session(&self, peer: PeerId) -> Option { + match self.session_id { + Some(id) if id == peer => self.session.clone(), + _ => self.sessions.read().unwrap().get(peer).cloned(), + } + } + /// Send a packet over the network to another peer. pub fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), UtilError> { - let session = { self.sessions.read().unwrap().get(peer).cloned() }; + let session = self.resolve_session(peer); if let Some(session) = session { - session.lock().unwrap().deref_mut().send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| { - warn!(target: "network", "Send error: {:?}", e); - }); //TODO: don't copy vector data + try!(session.lock().unwrap().deref_mut().send_packet(self.protocol, packet_id as u8, &data)); try!(self.io.update_registration(peer)); } else { trace!(target: "network", "Send: Peer no longer exist") @@ -200,14 +208,10 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone Ok(()) } - /// Respond to a current network message. Panics if no there is no packet in the context. + /// Respond to a current network message. Panics if no there is no packet in the context. If the session is expired returns nothing. pub fn respond(&self, packet_id: PacketId, data: Vec) -> Result<(), UtilError> { - match self.session { - Some(session) => self.send(session, packet_id, data), - None => { - panic!("Respond: Session does not exist") - } - } + assert!(self.session.is_some(), "Respond called without network context"); + self.send(self.session_id.unwrap(), packet_id, data) } /// Send an IO message @@ -215,7 +219,6 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone self.io.message(NetworkIoMessage::User(msg)); } - /// Disable current protocol capability for given peer. If no capabilities left peer gets disconnected. pub fn disable_peer(&self, peer: PeerId) { //TODO: remove capability, disconnect if no capabilities left @@ -239,7 +242,7 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone /// Returns peer identification string pub fn peer_info(&self, peer: PeerId) -> String { - let session = { self.sessions.read().unwrap().get(peer).cloned() }; + let session = self.resolve_session(peer); if let Some(session) = session { return session.lock().unwrap().info.client_version.clone() } @@ -624,7 +627,7 @@ impl Host where Message: Send + Sync + Clone { let mut packet_data: Option<(ProtocolId, PacketId, Vec)> = None; let mut kill = false; let session = { self.sessions.read().unwrap().get(token).cloned() }; - if let Some(session) = session { + if let Some(session) = session.clone() { let mut s = session.lock().unwrap(); match s.readable(io, &self.info.read().unwrap()) { Err(e) => { @@ -656,11 +659,11 @@ impl Host where Message: Send + Sync + Clone { } for p in ready_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.connected(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token); + h.connected(&NetworkContext::new(io, p, session.clone(), self.sessions.clone()), &token); } if let Some((p, packet_id, data)) = packet_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.read(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token, packet_id, &data[1..]); + h.read(&NetworkContext::new(io, p, session.clone(), self.sessions.clone()), &token, packet_id, &data[1..]); } io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); } @@ -718,6 +721,7 @@ impl Host where Message: Send + Sync + Clone { let mut to_disconnect: Vec = Vec::new(); let mut failure_id = None; let mut deregister = false; + let mut expired_session = None; match token { FIRST_HANDSHAKE ... LAST_HANDSHAKE => { let handshakes = self.handshakes.write().unwrap(); @@ -733,6 +737,7 @@ impl Host where Message: Send + Sync + Clone { FIRST_SESSION ... LAST_SESSION => { let sessions = self.sessions.write().unwrap(); if let Some(session) = sessions.get(token).cloned() { + expired_session = Some(session.clone()); let mut s = session.lock().unwrap(); if !s.expired() { if s.is_ready() { @@ -757,7 +762,7 @@ impl Host where Message: Send + Sync + Clone { } for p in to_disconnect { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.disconnected(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token); + h.disconnected(&NetworkContext::new(io, p, expired_session.clone(), self.sessions.clone()), &token); } if deregister { io.deregister_stream(token).expect("Error deregistering stream"); diff --git a/util/src/network/session.rs b/util/src/network/session.rs index edf929a9a..84c063c92 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -213,6 +213,9 @@ impl Session { /// Send a protocol packet to peer. pub fn send_packet(&mut self, protocol: &str, packet_id: u8, data: &[u8]) -> Result<(), UtilError> { + if self.expired() { + return Err(From::from(NetworkError::Expired)); + } let mut i = 0usize; while protocol != self.info.capabilities[i].protocol { i += 1; @@ -351,15 +354,15 @@ impl Session { offset += caps[i].packet_count; i += 1; } - trace!(target: "net", "Hello: {} v{} {} {:?}", client_version, protocol, id, caps); + trace!(target: "network", "Hello: {} v{} {} {:?}", client_version, protocol, id, caps); self.info.client_version = client_version; self.info.capabilities = caps; if self.info.capabilities.is_empty() { - trace!("No common capabilities with peer."); + trace!(target: "network", "No common capabilities with peer."); return Err(From::from(self.disconnect(DisconnectReason::UselessPeer))); } if protocol != host.protocol_version { - trace!("Peer protocol version mismatch: {}", protocol); + trace!(target: "network", "Peer protocol version mismatch: {}", protocol); return Err(From::from(self.disconnect(DisconnectReason::UselessPeer))); } self.had_hello = true; From aaf2e0c3fbdc0cd3e125988e96987486d73bf395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 6 Mar 2016 11:04:13 +0100 Subject: [PATCH 397/753] Locking outside of loop --- sync/src/chain.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index ddf30854a..a8bcb653f 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -933,9 +933,11 @@ impl ChainSync { let item_count = r.item_count(); trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count); let fetch_latest_nonce = |a : &Address| chain.nonce(a); + + let mut transaction_queue = self.transaction_queue.lock().unwrap(); for i in 0..item_count { let tx: SignedTransaction = try!(r.val_at(i)); - self.transaction_queue.lock().unwrap().add(tx, &fetch_latest_nonce); + transaction_queue.add(tx, &fetch_latest_nonce); } Ok(()) } From e91de785281d59b591079c16c798d7252991b593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 6 Mar 2016 11:11:59 +0100 Subject: [PATCH 398/753] Renaming back bad as retracted --- ethcore/src/client.rs | 4 +++- ethcore/src/service.rs | 2 ++ sync/src/chain.rs | 10 +++++----- sync/src/lib.rs | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 852ba6a36..123847a7f 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -413,7 +413,9 @@ impl Client where V: Verifier { if !good_blocks.is_empty() && block_queue.queue_info().is_empty() { io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { good: good_blocks, - retracted: bad_blocks, + bad: bad_blocks, + // TODO [todr] were to take those from? + retracted: vec![], })).unwrap(); } } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index a80adb0ba..443d09e3b 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -30,6 +30,8 @@ pub enum SyncMessage { /// Hashes of blocks imported to blockchain good: Vec, /// Hashes of blocks not imported to blockchain + bad: Vec, + /// Hashes of blocks that were removed from canonical chain retracted: Vec, }, /// A block is ready diff --git a/sync/src/chain.rs b/sync/src/chain.rs index a8bcb653f..fcc9f49c8 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1267,7 +1267,7 @@ impl ChainSync { } /// called when block is imported to chain, updates transactions queue - pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], retracted: &[H256]) { + pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], bad: &[H256], _retracted: &[H256]) { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockId::Hash(hash.clone())) @@ -1280,14 +1280,14 @@ impl ChainSync { let chain = io.chain(); let good = good.par_iter().map(|h| fetch_transactions(chain, h)); - let retracted = retracted.par_iter().map(|h| fetch_transactions(chain, h)); + let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); good.for_each(|txs| { let mut transaction_queue = self.transaction_queue.lock().unwrap(); let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); }); - retracted.for_each(|txs| { + bad.for_each(|txs| { // populate sender for tx in &txs { let _sender = tx.sender(); @@ -1637,10 +1637,10 @@ mod tests { let io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&io, &[], &good_blocks); + sync.chain_new_blocks(&io, &[], &good_blocks, &[]); assert_eq!(sync.transaction_queue.lock().unwrap().status().future, 0); assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); - sync.chain_new_blocks(&io, &good_blocks, &retracted_blocks); + sync.chain_new_blocks(&io, &good_blocks, &retracted_blocks, &[]); // then let status = sync.transaction_queue.lock().unwrap().status(); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index d67a09f3b..8a30385a2 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -157,9 +157,9 @@ impl NetworkProtocolHandler for EthSync { SyncMessage::BlockVerified => { self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); }, - SyncMessage::NewChainBlocks { ref good, ref retracted } => { + SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted } => { let sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&sync_io, good, retracted); + self.sync.write().unwrap().chain_new_blocks(&sync_io, good, bad, retracted); } } } From d77d9ad9d84105f2c0b4cd53b90f835e3087f669 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 6 Mar 2016 17:28:50 +0100 Subject: [PATCH 399/753] JournalDB with history overlay --- ethcore/src/client.rs | 8 +- parity/main.rs | 3 +- util/src/journaldb.rs | 326 ++++++++++++++++++++++++++---------------- util/src/memorydb.rs | 6 + 4 files changed, 216 insertions(+), 127 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 858185873..2b5ec5ccb 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -190,6 +190,8 @@ pub struct ClientReport { pub transactions_applied: usize, /// How much gas has been processed so far. pub gas_processed: U256, + /// Memory used by state DB + pub state_db_mem: usize, } impl ClientReport { @@ -222,7 +224,7 @@ pub struct Client where V: Verifier { } const HISTORY: u64 = 1000; -const CLIENT_DB_VER_STR: &'static str = "4.0"; +const CLIENT_DB_VER_STR: &'static str = "5.0"; impl Client { /// Create a new client with given spec and DB path. @@ -432,7 +434,9 @@ impl Client where V: Verifier { /// Get the report. pub fn report(&self) -> ClientReport { - self.report.read().unwrap().clone() + let mut report = self.report.read().unwrap().clone(); + report.state_db_mem = self.state_db.lock().unwrap().mem_used(); + report } /// Tick the client. diff --git a/parity/main.rs b/parity/main.rs index 3f4243a0a..605fb315d 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -395,7 +395,7 @@ impl Informant { let sync_info = sync.status(); if let (_, _, &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { - println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} chain, {} queue, {} sync ]", + println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} db, {} chain, {} queue, {} sync ]", chain_info.best_block_number, chain_info.best_block_hash, (report.blocks_imported - last_report.blocks_imported) / dur, @@ -408,6 +408,7 @@ impl Informant { queue_info.unverified_queue_size, queue_info.verified_queue_size, + Informant::format_bytes(report.state_db_mem), Informant::format_bytes(cache_info.total()), Informant::format_bytes(queue_info.mem_used), Informant::format_bytes(sync_info.mem_used), diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 01e53f819..48bd94d64 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -35,17 +35,36 @@ use std::env; /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. pub struct JournalDB { - overlay: MemoryDB, + transaction_overlay: MemoryDB, backing: Arc, - counters: Option>>>, + journal_overlay: Option>>, +} + +struct JournalOverlay { + backing_overlay: MemoryDB, + journal: VecDeque +} + +struct JournalEntry { + id: H256, + index: usize, + era: u64, + insertions: Vec, + deletions: Vec, +} + +impl HeapSizeOf for JournalEntry { + fn heap_size_of_children(&self) -> usize { + self.insertions.heap_size_of_children() + self.deletions.heap_size_of_children() + } } impl Clone for JournalDB { fn clone(&self) -> JournalDB { JournalDB { - overlay: MemoryDB::new(), + transaction_overlay: MemoryDB::new(), backing: self.backing.clone(), - counters: self.counters.clone(), + journal_overlay: self.journal_overlay.clone(), } } } @@ -60,7 +79,6 @@ const DB_VERSION_NO_JOURNAL : u32 = 3 + 256; const PADDING : [u8; 10] = [ 0u8; 10 ]; impl JournalDB { - /// Create a new instance from file pub fn new(path: &str) -> JournalDB { Self::from_prefs(path, true) @@ -86,15 +104,16 @@ impl JournalDB { with_journal = prefer_journal; } - let counters = if with_journal { - Some(Arc::new(RwLock::new(JournalDB::read_counters(&backing)))) + + let journal_overlay = if with_journal { + Some(Arc::new(RwLock::new(JournalDB::read_overlay(&backing)))) } else { None }; JournalDB { - overlay: MemoryDB::new(), + transaction_overlay: MemoryDB::new(), backing: Arc::new(backing), - counters: counters, + journal_overlay: journal_overlay, } } @@ -113,71 +132,48 @@ impl JournalDB { /// Commit all recent insert operations. pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - let have_counters = self.counters.is_some(); - if have_counters { - self.commit_with_counters(now, id, end) + let have_journal_overlay = self.journal_overlay.is_some(); + if have_journal_overlay { + self.commit_with_overlay(now, id, end) } else { - self.commit_without_counters() + self.commit_without_overlay() } } /// Drain the overlay and place it into a batch for the DB. fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> usize { - let mut inserts = 0usize; - let mut deletes = 0usize; + let mut insertions = 0usize; + let mut deletions = 0usize; for i in overlay.drain().into_iter() { let (key, (value, rc)) = i; if rc > 0 { assert!(rc == 1); batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); - inserts += 1; + insertions += 1; } if rc < 0 { assert!(rc == -1); - deletes += 1; + deletions += 1; } } - trace!("commit: Inserted {}, Deleted {} nodes", inserts, deletes); - inserts + deletes + trace!("commit: Inserted {}, Deleted {} nodes", insertions, deletions); + insertions + deletions } - /// Just commit the overlay into the backing DB. - fn commit_without_counters(&mut self) -> Result { + /// Just commit the transaction overlay into the backing DB. + fn commit_without_overlay(&mut self) -> Result { let batch = DBTransaction::new(); - let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); + let ret = Self::batch_overlay_insertions(&mut self.transaction_overlay, &batch); try!(self.backing.write(batch)); Ok(ret as u32) } /// Commit all recent insert operations and historical removals from the old era /// to the backing database. - fn commit_with_counters(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: - // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, n] => [ ... ] - - // TODO: store reclaim_period. - - // when we make a new commit, we journal the inserts and removes. - // for each end_era that we journaled that we are no passing by, - // we remove all of its removes assuming it is canonical and all - // of its inserts otherwise. - // - // We also keep reference counters for each key inserted in the journal to handle - // the following cases where key K must not be deleted from the DB when processing removals : - // Given H is the journal size in eras, 0 <= C <= H. - // Key K is removed in era A(N) and re-inserted in canonical era B(N + C). - // Key K is removed in era A(N) and re-inserted in non-canonical era B`(N + C). - // Key K is added in non-canonical era A'(N) canonical B(N + C). - // - // The counter is encreased each time a key is inserted in the journal in the commit. The list of insertions - // is saved with the era record. When the era becomes end_era and goes out of journal the counter is decreased - // and the key is safe to delete. - + fn commit_with_overlay(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // record new commit's details. trace!("commit: #{} ({}), end era: {:?}", now, id, end); - let mut counters = self.counters.as_ref().unwrap().write().unwrap(); + let mut journal_overlay = self.journal_overlay.as_mut().unwrap().write().unwrap(); let batch = DBTransaction::new(); { let mut index = 0usize; @@ -204,90 +200,83 @@ impl JournalDB { } let mut r = RlpStream::new_list(3); - let inserts: Vec = self.overlay.keys().iter().filter(|&(_, &c)| c > 0).map(|(key, _)| key.clone()).collect(); + let mut tx = self.transaction_overlay.drain(); + let inserted_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c > 0 { Some(k.clone()) } else { None }).collect(); + let removed_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c < 0 { Some(k.clone()) } else { None }).collect(); // Increase counter for each inserted key no matter if the block is canonical or not. - for i in &inserts { - *counters.entry(i.clone()).or_insert(0) += 1; - } - let removes: Vec = self.overlay.keys().iter().filter(|&(_, &c)| c < 0).map(|(key, _)| key.clone()).collect(); + let insertions = tx.drain().filter_map(|(k, (v, c))| if c > 0 { Some((k, v)) } else { None }); r.append(id); - r.append(&inserts); - r.append(&removes); + r.begin_list(inserted_keys.len()); + for (k, v) in insertions { + r.begin_list(2); + r.append(&k); + r.append(&v); + journal_overlay.backing_overlay.emplace(k, v); + } + r.append(&removed_keys); try!(batch.put(&last, r.as_raw())); try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + journal_overlay.journal.push_back(JournalEntry { id: id.clone(), index: index, era: now, insertions: inserted_keys, deletions: removed_keys }); } // apply old commits' details + if let Some((end_era, canon_id)) = end { - let mut index = 0usize; - let mut last; - let mut to_remove: Vec = Vec::new(); - let mut canon_inserts: Vec = Vec::new(); - while let Some(rlp_data) = try!(self.backing.get({ + let mut canon_insertions: Vec<(H256, Bytes)> = Vec::new(); + let mut canon_deletions: Vec = Vec::new(); + let mut overlay_deletions: Vec = Vec::new(); + while journal_overlay.journal.front().map_or(false, |e| e.era <= end_era) { + let mut journal = journal_overlay.journal.pop_front().unwrap(); + //delete the record from the db let mut r = RlpStream::new_list(3); - r.append(&end_era); - r.append(&index); + r.append(&journal.era); + r.append(&journal.index); r.append(&&PADDING[..]); - last = r.drain(); - &last - })) { - let rlp = Rlp::new(&rlp_data); - let mut inserts: Vec = rlp.val_at(1); - JournalDB::decrease_counters(&inserts, &mut counters); - // Collect keys to be removed. These are removed keys for canonical block, inserted for non-canonical - if canon_id == rlp.val_at(0) { - let mut canon_deletes: Vec = rlp.val_at(2); - trace!("Purging nodes deleted from canon: {:?}", canon_deletes); - to_remove.append(&mut canon_deletes); - canon_inserts = inserts; + try!(batch.delete(&r.drain())); + trace!("commit: Delete journal for time #{}.{}: {}, (canon was {}): +{} -{} entries", end_era, journal.index, journal.id, canon_id, journal.insertions.len(), journal.deletions.len()); + { + if canon_id == journal.id { + for h in &journal.insertions { + match journal_overlay.backing_overlay.raw(&h) { + Some(&(ref d, rc)) if rc > 0 => canon_insertions.push((h.clone(), d.clone())), //TODO: optimizie this to avoid data copy + _ => () + } + } + canon_deletions = journal.deletions; + } + overlay_deletions.append(&mut journal.insertions); } - else { - trace!("Purging nodes inserted in non-canon: {:?}", inserts); - to_remove.append(&mut inserts); + if canon_id == journal.id { } - trace!("commit: Delete journal for time #{}.{}: {}, (canon was {}): {} entries", end_era, index, rlp.val_at::(0), canon_id, to_remove.len()); - try!(batch.delete(&last)); - index += 1; } - - let canon_inserts = canon_inserts.drain(..).collect::>(); - // Purge removed keys if they are not referenced and not re-inserted in the canon commit - let mut deletes = 0; - trace!("Purging filtered nodes: {:?}", to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)).collect::>()); - for h in to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)) { - try!(batch.delete(&h)); - deletes += 1; + // apply canon inserts first + for (k, v) in canon_insertions { + try!(batch.put(&k, &v)); } - trace!("Total nodes purged: {}", deletes); + // clean the overlay + for k in overlay_deletions { + journal_overlay.backing_overlay.kill(&k); + } + // apply removes + for k in canon_deletions { + if !journal_overlay.backing_overlay.exists(&k) { + try!(batch.delete(&k)); + } + } + journal_overlay.backing_overlay.purge(); } - - // Commit overlay insertions - let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); try!(self.backing.write(batch)); - Ok(ret as u32) - } - - - // Decrease counters for given keys. Deletes obsolete counters - fn decrease_counters(keys: &[H256], counters: &mut HashMap) { - for i in keys.iter() { - let delete_counter = { - let cnt = counters.get_mut(i).expect("Missing key counter"); - *cnt -= 1; - *cnt == 0 - }; - if delete_counter { - counters.remove(i); - } - } + Ok(0 as u32) } fn payload(&self, key: &H256) -> Option { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } - fn read_counters(db: &Database) -> HashMap { - let mut res = HashMap::new(); + fn read_overlay(db: &Database) -> JournalOverlay { + let mut journal = VecDeque::new(); + let mut overlay = MemoryDB::new(); + let mut count = 0; if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { let mut era = decode::(&val); loop { @@ -300,10 +289,24 @@ impl JournalDB { &r.drain() }).expect("Low-level database error.") { let rlp = Rlp::new(&rlp_data); - let to_add: Vec = rlp.val_at(1); - for h in to_add { - *res.entry(h).or_insert(0) += 1; + let id: H256 = rlp.val_at(0); + let insertions = rlp.at(1); + let deletions: Vec = rlp.val_at(2); + let mut inserted_keys = Vec::new(); + for r in insertions.iter() { + let k: H256 = r.val_at(0); + let v: Bytes = r.val_at(1); + overlay.emplace(k.clone(), v); + inserted_keys.push(k); + count += 1; } + journal.push_front(JournalEntry { + id: id, + index: index, + era: era, + insertions: inserted_keys, + deletions: deletions, + }); index += 1; }; if index == 0 || era == 0 { @@ -312,8 +315,19 @@ impl JournalDB { era -= 1; } } - trace!("Recovered {} counters", res.len()); - res + trace!("Recovered {} overlay entries, {} journal entries", count, journal.len()); + JournalOverlay { backing_overlay: overlay, journal: journal } + } + + /// Returns heap memory size used + pub fn mem_used(&self) -> usize { + let mut mem = self.transaction_overlay.mem_used(); + if let Some(ref overlay) = self.journal_overlay.as_ref() { + let overlay = overlay.read().unwrap(); + mem += overlay.backing_overlay.mem_used(); + mem += overlay.journal.heap_size_of_children(); + } + mem } } @@ -325,7 +339,7 @@ impl HashDB for JournalDB { ret.insert(h, 1); } - for (key, refs) in self.overlay.keys().into_iter() { + for (key, refs) in self.transaction_overlay.keys().into_iter() { let refs = *ret.get(&key).unwrap_or(&0) + refs; ret.insert(key, refs); } @@ -333,15 +347,23 @@ impl HashDB for JournalDB { } fn lookup(&self, key: &H256) -> Option<&[u8]> { - let k = self.overlay.raw(key); + let k = self.transaction_overlay.raw(key); match k { Some(&(ref d, rc)) if rc > 0 => Some(d), _ => { - if let Some(x) = self.payload(key) { - Some(&self.overlay.denote(key, x).0) - } - else { - None + let v = self.journal_overlay.as_ref().map_or(None, |ref j| j.read().unwrap().backing_overlay.lookup(key).map(|v| v.to_vec())); + match v { + Some(x) => { + Some(&self.transaction_overlay.denote(key, x).0) + } + _ => { + if let Some(x) = self.payload(key) { + Some(&self.transaction_overlay.denote(key, x).0) + } + else { + None + } + } } } } @@ -352,13 +374,13 @@ impl HashDB for JournalDB { } fn insert(&mut self, value: &[u8]) -> H256 { - self.overlay.insert(value) + self.transaction_overlay.insert(value) } fn emplace(&mut self, key: H256, value: Bytes) { - self.overlay.emplace(key, value); + self.transaction_overlay.emplace(key, value); } fn kill(&mut self, key: &H256) { - self.overlay.kill(key); + self.transaction_overlay.kill(key); } } @@ -492,11 +514,13 @@ mod tests { fn reopen() { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); + let bar = H256::random(); let foo = { let mut jdb = JournalDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); + jdb.emplace(bar.clone(), b"bar".to_vec()); jdb.commit(0, &b"0".sha3(), None).unwrap(); foo }; @@ -510,8 +534,62 @@ mod tests { { let mut jdb = JournalDB::new(dir.to_str().unwrap()); assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); assert!(!jdb.exists(&foo)); } } + + #[test] + fn reopen_remove() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let bar = H256::random(); + + let foo = { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + foo + }; + + { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(!jdb.exists(&foo)); + } + } + #[test] + fn reopen_fork() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let (foo, bar, baz) = { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + (foo, bar, baz) + }; + + { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } + } } diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index 680a6e1d0..9cd018935 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -21,6 +21,7 @@ use bytes::*; use rlp::*; use sha3::*; use hashdb::*; +use heapsize::*; use std::mem; use std::collections::HashMap; @@ -143,6 +144,11 @@ impl MemoryDB { } self.raw(key).unwrap() } + + /// Returns the size of allocated heap memory + pub fn mem_used(&self) -> usize { + self.data.heap_size_of_children() + } } static NULL_RLP_STATIC: [u8; 1] = [0x80; 1]; From 51c95d4d67643f03fc0fd11cf241308acb01eb5a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 6 Mar 2016 21:57:55 +0100 Subject: [PATCH 400/753] Implement option 1. --- util/src/journaldb.rs | 393 +++++++++++++++++++++--------------------- 1 file changed, 194 insertions(+), 199 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 01e53f819..5f94dcbeb 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -20,15 +20,12 @@ use common::*; use rlp::*; use hashdb::*; use memorydb::*; -use kvdb::{Database, DBTransaction, DatabaseConfig}; +use rocksdb::{DB, Writable, WriteBatch, IteratorMode}; #[cfg(test)] use std::env; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay -/// and, possibly, latent-removal semantics. -/// -/// If `counters` is `None`, then it behaves exactly like OverlayDB. If not it behaves -/// differently: +/// and latent-removal semantics. /// /// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect @@ -36,8 +33,8 @@ use std::env; /// the removals actually take effect. pub struct JournalDB { overlay: MemoryDB, - backing: Arc, - counters: Option>>>, + backing: Arc, + counters: Arc>>, } impl Clone for JournalDB { @@ -50,51 +47,33 @@ impl Clone for JournalDB { } } -// all keys must be at least 12 bytes -const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; -const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const LAST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; +const VERSION_KEY : [u8; 4] = [ b'j', b'v', b'e', b'r' ]; -const DB_VERSION : u32 = 3; -const DB_VERSION_NO_JOURNAL : u32 = 3 + 256; - -const PADDING : [u8; 10] = [ 0u8; 10 ]; +const DB_VERSION: u32 = 1; impl JournalDB { - - /// Create a new instance from file - pub fn new(path: &str) -> JournalDB { - Self::from_prefs(path, true) + /// Create a new instance given a `backing` database. + pub fn new(backing: DB) -> JournalDB { + let db = Arc::new(backing); + JournalDB::new_with_arc(db) } - /// Create a new instance from file - pub fn from_prefs(path: &str, prefer_journal: bool) -> JournalDB { - let opts = DatabaseConfig { - prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix - }; - let backing = Database::open(&opts, path).unwrap_or_else(|e| { - panic!("Error opening state db: {}", e); - }); - let with_journal; - if !backing.is_empty() { + /// Create a new instance given a shared `backing` database. + pub fn new_with_arc(backing: Arc) -> JournalDB { + if backing.iterator(IteratorMode::Start).next().is_some() { match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { - Ok(Some(DB_VERSION)) => { with_journal = true; }, - Ok(Some(DB_VERSION_NO_JOURNAL)) => { with_journal = false; }, + Ok(Some(DB_VERSION)) => {}, v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) } } else { - backing.put(&VERSION_KEY, &encode(&(if prefer_journal { DB_VERSION } else { DB_VERSION_NO_JOURNAL }))).expect("Error writing version to database"); - with_journal = prefer_journal; + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } - - let counters = if with_journal { - Some(Arc::new(RwLock::new(JournalDB::read_counters(&backing)))) - } else { - None - }; + let counters = JournalDB::read_counters(&backing); JournalDB { overlay: MemoryDB::new(), - backing: Arc::new(backing), - counters: counters, + backing: backing, + counters: Arc::new(RwLock::new(counters)), } } @@ -103,55 +82,93 @@ impl JournalDB { pub fn new_temp() -> JournalDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); - Self::new(dir.to_str().unwrap()) + Self::new(DB::open_default(dir.to_str().unwrap()).unwrap()) } /// Check if this database has any commits pub fn is_empty(&self) -> bool { - self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + self.backing.get(&LAST_ERA_KEY).expect("Low level database error").is_none() } - /// Commit all recent insert operations. - pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - let have_counters = self.counters.is_some(); - if have_counters { - self.commit_with_counters(now, id, end) - } else { - self.commit_without_counters() + fn morph_key(key: &H256, index: u8) -> Bytes { + let mut ret = key.bytes().to_owned(); + ret.push(index); + ret + } + + // The next three are valid only as long as there is an insert operation of `key` in the journal. + fn set_already_in(batch: &WriteBatch, key: &H256) { batch.put(&Self::morph_key(key, 0), &[1u8]); } + fn reset_already_in(batch: &WriteBatch, key: &H256) { batch.delete(&Self::morph_key(key, 0)); } + fn is_already_in(backing: &DB, key: &H256) -> bool { + backing.get(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?").is_some() + } + + fn insert_keys(inserts: &Vec<(H256, Bytes)>, backing: &DB, counters: &mut HashMap, batch: &WriteBatch) { + for &(ref h, ref d) in inserts { + if let Some(c) = counters.get_mut(h) { + // already counting. increment. + *c += 1; + continue; + } + + // this is the first entry for this node in the journal. + if backing.get(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?").is_some() { + // already in the backing DB. start counting, and remember it was already in. + Self::set_already_in(batch, &h); + counters.insert(h.clone(), 1); + continue; + } + + // Gets removed when a key leaves the journal, so should never be set when we're placing a new key. + //Self::reset_already_in(&h); + assert!(!Self::is_already_in(backing, &h)); + batch.put(&h.bytes(), d); } } - /// Drain the overlay and place it into a batch for the DB. - fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> usize { - let mut inserts = 0usize; - let mut deletes = 0usize; - for i in overlay.drain().into_iter() { - let (key, (value, rc)) = i; - if rc > 0 { - assert!(rc == 1); - batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); - inserts += 1; - } - if rc < 0 { - assert!(rc == -1); - deletes += 1; + fn replay_keys(inserts: &Vec, backing: &DB, counters: &mut HashMap) { + for h in inserts { + if let Some(c) = counters.get_mut(h) { + // already counting. increment. + *c += 1; + continue; } + + // this is the first entry for this node in the journal. + // it is initialised to 1 if it was already in. + counters.insert(h.clone(), if Self::is_already_in(backing, h) {1} else {0}); } - trace!("commit: Inserted {}, Deleted {} nodes", inserts, deletes); - inserts + deletes } - /// Just commit the overlay into the backing DB. - fn commit_without_counters(&mut self) -> Result { - let batch = DBTransaction::new(); - let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); - try!(self.backing.write(batch)); - Ok(ret as u32) + fn kill_keys(deletes: Vec, counters: &mut HashMap, batch: &WriteBatch) { + for h in deletes.into_iter() { + let mut n: Option = None; + if let Some(c) = counters.get_mut(&h) { + if *c > 1 { + *c -= 1; + continue; + } else { + n = Some(*c); + } + } + match &n { + &Some(i) if i == 1 => { + counters.remove(&h); + Self::reset_already_in(batch, &h); + } + &None => { + // Gets removed when moving from 1 to 0 additional refs. Should never be here at 0 additional refs. + //assert!(!Self::is_already_in(db, &h)); + batch.delete(&h.bytes()); + } + _ => panic!("Invalid value in counters: {:?}", n), + } + } } /// Commit all recent insert operations and historical removals from the old era /// to the backing database. - fn commit_with_counters(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] @@ -159,62 +176,84 @@ impl JournalDB { // TODO: store reclaim_period. - // when we make a new commit, we journal the inserts and removes. - // for each end_era that we journaled that we are no passing by, - // we remove all of its removes assuming it is canonical and all - // of its inserts otherwise. + // When we make a new commit, we make a journal of all blocks in the recent history and record + // all keys that were inserted and deleted. The journal is ordered by era; multiple commits can + // share the same era. This forms a data structure similar to a queue but whose items are tuples. + // By the time comes to remove a tuple from the queue (i.e. then the era passes from recent history + // into ancient history) then only one commit from the tuple is considered canonical. This commit + // is kept in the main backing database, whereas any others from the same era are reverted. + // + // It is possible that a key, properly available in the backing database be deleted and re-inserted + // in the recent history queue, yet have both operations in commits that are eventually non-canonical. + // To avoid the original, and still required, key from being deleted, we maintain a reference count + // which includes an original key, if any. + // + // The semantics of the `counter` are: + // insert key k: + // counter already contains k: count += 1 + // counter doesn't contain k: + // backing db contains k: count = 1 + // backing db doesn't contain k: insert into backing db, count = 0 + // delete key k: + // counter contains k (count is asserted to be non-zero): + // count > 1: counter -= 1 + // count == 1: remove counter + // count == 0: remove key from backing db + // counter doesn't contain k: remove key from backing db // - // We also keep reference counters for each key inserted in the journal to handle - // the following cases where key K must not be deleted from the DB when processing removals : - // Given H is the journal size in eras, 0 <= C <= H. - // Key K is removed in era A(N) and re-inserted in canonical era B(N + C). - // Key K is removed in era A(N) and re-inserted in non-canonical era B`(N + C). - // Key K is added in non-canonical era A'(N) canonical B(N + C). + // Practically, this means that for each commit block turning from recent to ancient we do the + // following: + // is_canonical: + // inserts: Ignored (left alone in the backing database). + // deletes: Enacted; however, recent history queue is checked for ongoing references. This is + // reduced as a preference to deletion from the backing database. + // !is_canonical: + // inserts: Reverted; however, recent history queue is checked for ongoing references. This is + // reduced as a preference to deletion from the backing database. + // deletes: Ignored (they were never inserted). // - // The counter is encreased each time a key is inserted in the journal in the commit. The list of insertions - // is saved with the era record. When the era becomes end_era and goes out of journal the counter is decreased - // and the key is safe to delete. // record new commit's details. - trace!("commit: #{} ({}), end era: {:?}", now, id, end); - let mut counters = self.counters.as_ref().unwrap().write().unwrap(); - let batch = DBTransaction::new(); + let batch = WriteBatch::new(); + let mut counters = self.counters.write().unwrap(); { let mut index = 0usize; let mut last; - while { - let record = try!(self.backing.get({ - let mut r = RlpStream::new_list(3); - r.append(&now); - r.append(&index); - r.append(&&PADDING[..]); - last = r.drain(); - &last - })); - match record { - Some(r) => { - assert!(&Rlp::new(&r).val_at::(0) != id); - true - }, - None => false, - } - } { + while try!(self.backing.get({ + let mut r = RlpStream::new_list(2); + r.append(&now); + r.append(&index); + last = r.drain(); + &last + })).is_some() { index += 1; } + let drained = self.overlay.drain(); + let removes: Vec = drained + .iter() + .filter_map(|(ref k, &(_, ref c))| if *c < 0 {Some(k.clone())} else {None}).cloned() + .collect(); + let inserts: Vec<(H256, Bytes)> = drained + .into_iter() + .filter_map(|(k, (v, r))| if r > 0 { assert!(r == 1); Some((k, v)) } else { assert!(r >= -1); None }) + .collect(); + let mut r = RlpStream::new_list(3); - let inserts: Vec = self.overlay.keys().iter().filter(|&(_, &c)| c > 0).map(|(key, _)| key.clone()).collect(); - // Increase counter for each inserted key no matter if the block is canonical or not. - for i in &inserts { - *counters.entry(i.clone()).or_insert(0) += 1; - } - let removes: Vec = self.overlay.keys().iter().filter(|&(_, &c)| c < 0).map(|(key, _)| key.clone()).collect(); r.append(id); - r.append(&inserts); + + // Process the new inserts. + // We use the inserts for three things. For each: + // - we place into the backing DB or increment the counter if already in; + // - we note in the backing db that it was already in; + // - we write the key into our journal for this block; + + r.begin_list(inserts.len()); + inserts.iter().foreach(|&(k, _)| {r.append(&k);}); r.append(&removes); + Self::insert_keys(&inserts, &self.backing, &mut counters, &batch); try!(batch.put(&last, r.as_raw())); - try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); } // apply old commits' details @@ -222,105 +261,66 @@ impl JournalDB { let mut index = 0usize; let mut last; let mut to_remove: Vec = Vec::new(); - let mut canon_inserts: Vec = Vec::new(); while let Some(rlp_data) = try!(self.backing.get({ - let mut r = RlpStream::new_list(3); + let mut r = RlpStream::new_list(2); r.append(&end_era); r.append(&index); - r.append(&&PADDING[..]); last = r.drain(); &last })) { let rlp = Rlp::new(&rlp_data); - let mut inserts: Vec = rlp.val_at(1); - JournalDB::decrease_counters(&inserts, &mut counters); + let inserts: Vec = rlp.val_at(1); + let deletes: Vec = rlp.val_at(2); // Collect keys to be removed. These are removed keys for canonical block, inserted for non-canonical - if canon_id == rlp.val_at(0) { - let mut canon_deletes: Vec = rlp.val_at(2); - trace!("Purging nodes deleted from canon: {:?}", canon_deletes); - to_remove.append(&mut canon_deletes); - canon_inserts = inserts; - } - else { - trace!("Purging nodes inserted in non-canon: {:?}", inserts); - to_remove.append(&mut inserts); - } - trace!("commit: Delete journal for time #{}.{}: {}, (canon was {}): {} entries", end_era, index, rlp.val_at::(0), canon_id, to_remove.len()); + Self::kill_keys(if canon_id == rlp.val_at(0) {deletes} else {inserts}, &mut counters, &batch); try!(batch.delete(&last)); index += 1; } - - let canon_inserts = canon_inserts.drain(..).collect::>(); - // Purge removed keys if they are not referenced and not re-inserted in the canon commit - let mut deletes = 0; - trace!("Purging filtered nodes: {:?}", to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)).collect::>()); - for h in to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)) { - try!(batch.delete(&h)); - deletes += 1; - } - trace!("Total nodes purged: {}", deletes); + try!(batch.put(&LAST_ERA_KEY, &encode(&end_era))); + trace!("JournalDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); } - // Commit overlay insertions - let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); try!(self.backing.write(batch)); - Ok(ret as u32) - } - - - // Decrease counters for given keys. Deletes obsolete counters - fn decrease_counters(keys: &[H256], counters: &mut HashMap) { - for i in keys.iter() { - let delete_counter = { - let cnt = counters.get_mut(i).expect("Missing key counter"); - *cnt -= 1; - *cnt == 0 - }; - if delete_counter { - counters.remove(i); - } - } +// trace!("JournalDB::commit() deleted {} nodes", deletes); + Ok(0) } fn payload(&self, key: &H256) -> Option { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } - fn read_counters(db: &Database) -> HashMap { - let mut res = HashMap::new(); - if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); + fn read_counters(db: &DB) -> HashMap { + let mut counters = HashMap::new(); + if let Some(val) = db.get(&LAST_ERA_KEY).expect("Low-level database error.") { + let mut era = decode::(&val) + 1; loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ - let mut r = RlpStream::new_list(3); + let mut r = RlpStream::new_list(2); r.append(&era); r.append(&index); - r.append(&&PADDING[..]); &r.drain() }).expect("Low-level database error.") { let rlp = Rlp::new(&rlp_data); - let to_add: Vec = rlp.val_at(1); - for h in to_add { - *res.entry(h).or_insert(0) += 1; - } + let inserts: Vec = rlp.val_at(1); + Self::replay_keys(&inserts, db, &mut counters); index += 1; }; - if index == 0 || era == 0 { + if index == 0 { break; } - era -= 1; + era += 1; } } - trace!("Recovered {} counters", res.len()); - res + trace!("Recovered {} counters", counters.len()); + counters } } impl HashDB for JournalDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); - for (key, _) in self.backing.iter() { + for (key, _) in self.backing.iterator(IteratorMode::Start) { let h = H256::from_slice(key.deref()); ret.insert(h, 1); } @@ -368,6 +368,28 @@ mod tests { use super::*; use hashdb::*; + #[test] + fn insert_same_in_fork() { + // history is 1 + let mut jdb = JournalDB::new_temp(); + + let x = jdb.insert(b"X"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + jdb.commit(3, &b"1002a".sha3(), Some((1, b"1".sha3()))).unwrap(); + jdb.commit(4, &b"1003a".sha3(), Some((2, b"2".sha3()))).unwrap(); + + jdb.remove(&x); + jdb.commit(3, &b"1002b".sha3(), Some((1, b"1".sha3()))).unwrap(); + let x = jdb.insert(b"X"); + jdb.commit(4, &b"1003b".sha3(), Some((2, b"2".sha3()))).unwrap(); + + jdb.commit(5, &b"1004a".sha3(), Some((3, b"1002a".sha3()))).unwrap(); + jdb.commit(6, &b"1005a".sha3(), Some((4, b"1003a".sha3()))).unwrap(); + + assert!(jdb.exists(&x)); + } + #[test] fn long_history() { // history is 3 @@ -487,31 +509,4 @@ mod tests { jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); assert!(jdb.exists(&foo)); } - - #[test] - fn reopen() { - let mut dir = ::std::env::temp_dir(); - dir.push(H32::random().hex()); - - let foo = { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); - // history is 1 - let foo = jdb.insert(b"foo"); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - foo - }; - - { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); - jdb.remove(&foo); - jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); - } - - { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); - assert!(jdb.exists(&foo)); - jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); - assert!(!jdb.exists(&foo)); - } - } } From bfd882c7e03dee68d39c8722e65c9b395ed8b438 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 6 Mar 2016 22:05:12 +0100 Subject: [PATCH 401/753] Fix warnings. --- util/src/journaldb.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 5f94dcbeb..b7e495503 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -97,8 +97,8 @@ impl JournalDB { } // The next three are valid only as long as there is an insert operation of `key` in the journal. - fn set_already_in(batch: &WriteBatch, key: &H256) { batch.put(&Self::morph_key(key, 0), &[1u8]); } - fn reset_already_in(batch: &WriteBatch, key: &H256) { batch.delete(&Self::morph_key(key, 0)); } + fn set_already_in(batch: &WriteBatch, key: &H256) { batch.put(&Self::morph_key(key, 0), &[1u8]).expect("Low-level database error. Some issue with your hard disk?"); } + fn reset_already_in(batch: &WriteBatch, key: &H256) { batch.delete(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?"); } fn is_already_in(backing: &DB, key: &H256) -> bool { backing.get(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?").is_some() } @@ -122,7 +122,7 @@ impl JournalDB { // Gets removed when a key leaves the journal, so should never be set when we're placing a new key. //Self::reset_already_in(&h); assert!(!Self::is_already_in(backing, &h)); - batch.put(&h.bytes(), d); + batch.put(&h.bytes(), d).expect("Low-level database error. Some issue with your hard disk?"); } } @@ -159,7 +159,7 @@ impl JournalDB { &None => { // Gets removed when moving from 1 to 0 additional refs. Should never be here at 0 additional refs. //assert!(!Self::is_already_in(db, &h)); - batch.delete(&h.bytes()); + batch.delete(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?"); } _ => panic!("Invalid value in counters: {:?}", n), } @@ -260,7 +260,6 @@ impl JournalDB { if let Some((end_era, canon_id)) = end { let mut index = 0usize; let mut last; - let mut to_remove: Vec = Vec::new(); while let Some(rlp_data) = try!(self.backing.get({ let mut r = RlpStream::new_list(2); r.append(&end_era); From bc2fb14b5d6fbfac97a9e1d03e8e3d93d2da0283 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 6 Mar 2016 22:39:04 +0100 Subject: [PATCH 402/753] Add memory usage reports. Update to be similar to master. --- ethcore/src/client.rs | 8 +- parity/main.rs | 3 +- util/src/journaldb.rs | 213 +++++++++++++++++++++++++++++++++++------- util/src/memorydb.rs | 6 ++ 4 files changed, 194 insertions(+), 36 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 858185873..9688cc527 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -190,6 +190,8 @@ pub struct ClientReport { pub transactions_applied: usize, /// How much gas has been processed so far. pub gas_processed: U256, + /// Memory used by state DB + pub state_db_mem: usize, } impl ClientReport { @@ -222,7 +224,7 @@ pub struct Client where V: Verifier { } const HISTORY: u64 = 1000; -const CLIENT_DB_VER_STR: &'static str = "4.0"; +const CLIENT_DB_VER_STR: &'static str = "5.1"; impl Client { /// Create a new client with given spec and DB path. @@ -432,7 +434,9 @@ impl Client where V: Verifier { /// Get the report. pub fn report(&self) -> ClientReport { - self.report.read().unwrap().clone() + let mut report = self.report.read().unwrap().clone(); + report.state_db_mem = self.state_db.lock().unwrap().mem_used(); + report } /// Tick the client. diff --git a/parity/main.rs b/parity/main.rs index 3f4243a0a..605fb315d 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -395,7 +395,7 @@ impl Informant { let sync_info = sync.status(); if let (_, _, &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { - println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} chain, {} queue, {} sync ]", + println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} db, {} chain, {} queue, {} sync ]", chain_info.best_block_number, chain_info.best_block_hash, (report.blocks_imported - last_report.blocks_imported) / dur, @@ -408,6 +408,7 @@ impl Informant { queue_info.unverified_queue_size, queue_info.verified_queue_size, + Informant::format_bytes(report.state_db_mem), Informant::format_bytes(cache_info.total()), Informant::format_bytes(queue_info.mem_used), Informant::format_bytes(sync_info.mem_used), diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index b7e495503..f04affb7b 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -20,7 +20,7 @@ use common::*; use rlp::*; use hashdb::*; use memorydb::*; -use rocksdb::{DB, Writable, WriteBatch, IteratorMode}; +use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; @@ -33,8 +33,8 @@ use std::env; /// the removals actually take effect. pub struct JournalDB { overlay: MemoryDB, - backing: Arc, - counters: Arc>>, + backing: Arc, + counters: Option>>>, } impl Clone for JournalDB { @@ -47,33 +47,50 @@ impl Clone for JournalDB { } } -const LAST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; -const VERSION_KEY : [u8; 4] = [ b'j', b'v', b'e', b'r' ]; +// all keys must be at least 12 bytes +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; -const DB_VERSION: u32 = 1; +const DB_VERSION : u32 = 3; +const DB_VERSION_NO_JOURNAL : u32 = 3 + 256; + +const PADDING : [u8; 10] = [ 0u8; 10 ]; impl JournalDB { - /// Create a new instance given a `backing` database. - pub fn new(backing: DB) -> JournalDB { - let db = Arc::new(backing); - JournalDB::new_with_arc(db) + /// Create a new instance from file + pub fn new(path: &str) -> JournalDB { + Self::from_prefs(path, true) } - /// Create a new instance given a shared `backing` database. - pub fn new_with_arc(backing: Arc) -> JournalDB { - if backing.iterator(IteratorMode::Start).next().is_some() { + /// Create a new instance from file + pub fn from_prefs(path: &str, prefer_journal: bool) -> JournalDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(&opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + let with_journal; + if !backing.is_empty() { match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { - Ok(Some(DB_VERSION)) => {}, + Ok(Some(DB_VERSION)) => { with_journal = true; }, + Ok(Some(DB_VERSION_NO_JOURNAL)) => { with_journal = false; }, v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) } } else { - backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + backing.put(&VERSION_KEY, &encode(&(if prefer_journal { DB_VERSION } else { DB_VERSION_NO_JOURNAL }))).expect("Error writing version to database"); + with_journal = prefer_journal; } - let counters = JournalDB::read_counters(&backing); + + let counters = if with_journal { + Some(Arc::new(RwLock::new(JournalDB::read_counters(&backing)))) + } else { + None + }; JournalDB { overlay: MemoryDB::new(), - backing: backing, - counters: Arc::new(RwLock::new(counters)), + backing: Arc::new(backing), + counters: counters, } } @@ -87,7 +104,45 @@ impl JournalDB { /// Check if this database has any commits pub fn is_empty(&self) -> bool { - self.backing.get(&LAST_ERA_KEY).expect("Low level database error").is_none() + self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + } + + /// Commit all recent insert operations. + pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + let have_counters = self.counters.is_some(); + if have_counters { + self.commit_with_counters(now, id, end) + } else { + self.commit_without_counters() + } + } + + /// Drain the overlay and place it into a batch for the DB. + fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> usize { + let mut inserts = 0usize; + let mut deletes = 0usize; + for i in overlay.drain().into_iter() { + let (key, (value, rc)) = i; + if rc > 0 { + assert!(rc == 1); + batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); + inserts += 1; + } + if rc < 0 { + assert!(rc == -1); + deletes += 1; + } + } + trace!("commit: Inserted {}, Deleted {} nodes", inserts, deletes); + inserts + deletes + } + + /// Just commit the overlay into the backing DB. + fn commit_without_counters(&mut self) -> Result { + let batch = DBTransaction::new(); + let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); + try!(self.backing.write(batch)); + Ok(ret as u32) } fn morph_key(key: &H256, index: u8) -> Bytes { @@ -97,13 +152,13 @@ impl JournalDB { } // The next three are valid only as long as there is an insert operation of `key` in the journal. - fn set_already_in(batch: &WriteBatch, key: &H256) { batch.put(&Self::morph_key(key, 0), &[1u8]).expect("Low-level database error. Some issue with your hard disk?"); } - fn reset_already_in(batch: &WriteBatch, key: &H256) { batch.delete(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?"); } - fn is_already_in(backing: &DB, key: &H256) -> bool { + fn set_already_in(batch: &DBTransaction, key: &H256) { batch.put(&Self::morph_key(key, 0), &[1u8]).expect("Low-level database error. Some issue with your hard disk?"); } + fn reset_already_in(batch: &DBTransaction, key: &H256) { batch.delete(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?"); } + fn is_already_in(backing: &Database, key: &H256) -> bool { backing.get(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?").is_some() } - fn insert_keys(inserts: &Vec<(H256, Bytes)>, backing: &DB, counters: &mut HashMap, batch: &WriteBatch) { + fn insert_keys(inserts: &Vec<(H256, Bytes)>, backing: &Database, counters: &mut HashMap, batch: &DBTransaction) { for &(ref h, ref d) in inserts { if let Some(c) = counters.get_mut(h) { // already counting. increment. @@ -126,7 +181,7 @@ impl JournalDB { } } - fn replay_keys(inserts: &Vec, backing: &DB, counters: &mut HashMap) { + fn replay_keys(inserts: &Vec, backing: &Database, counters: &mut HashMap) { for h in inserts { if let Some(c) = counters.get_mut(h) { // already counting. increment. @@ -140,7 +195,7 @@ impl JournalDB { } } - fn kill_keys(deletes: Vec, counters: &mut HashMap, batch: &WriteBatch) { + fn kill_keys(deletes: Vec, counters: &mut HashMap, batch: &DBTransaction) { for h in deletes.into_iter() { let mut n: Option = None; if let Some(c) = counters.get_mut(&h) { @@ -168,7 +223,7 @@ impl JournalDB { /// Commit all recent insert operations and historical removals from the old era /// to the backing database. - pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + fn commit_with_counters(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] @@ -214,8 +269,8 @@ impl JournalDB { // // record new commit's details. - let batch = WriteBatch::new(); - let mut counters = self.counters.write().unwrap(); + let batch = DBTransaction::new(); + let mut counters = self.counters.as_ref().unwrap().write().unwrap(); { let mut index = 0usize; let mut last; @@ -224,6 +279,7 @@ impl JournalDB { let mut r = RlpStream::new_list(2); r.append(&now); r.append(&index); + r.append(&&PADDING[..]); last = r.drain(); &last })).is_some() { @@ -264,6 +320,7 @@ impl JournalDB { let mut r = RlpStream::new_list(2); r.append(&end_era); r.append(&index); + r.append(&&PADDING[..]); last = r.drain(); &last })) { @@ -275,7 +332,7 @@ impl JournalDB { try!(batch.delete(&last)); index += 1; } - try!(batch.put(&LAST_ERA_KEY, &encode(&end_era))); + try!(batch.put(&LATEST_ERA_KEY, &encode(&end_era))); trace!("JournalDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); } @@ -288,9 +345,9 @@ impl JournalDB { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } - fn read_counters(db: &DB) -> HashMap { + fn read_counters(db: &Database) -> HashMap { let mut counters = HashMap::new(); - if let Some(val) = db.get(&LAST_ERA_KEY).expect("Low-level database error.") { + if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { let mut era = decode::(&val) + 1; loop { let mut index = 0usize; @@ -298,6 +355,7 @@ impl JournalDB { let mut r = RlpStream::new_list(2); r.append(&era); r.append(&index); + r.append(&&PADDING[..]); &r.drain() }).expect("Low-level database error.") { let rlp = Rlp::new(&rlp_data); @@ -314,12 +372,17 @@ impl JournalDB { trace!("Recovered {} counters", counters.len()); counters } -} + + /// Returns heap memory size used + pub fn mem_used(&self) -> usize { + self.overlay.mem_used() + match &self.counters { &Some(ref c) => c.read().unwrap().heap_size_of_children(), &None => 0 } + } + } impl HashDB for JournalDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); - for (key, _) in self.backing.iterator(IteratorMode::Start) { + for (key, _) in self.backing.iter() { let h = H256::from_slice(key.deref()); ret.insert(h, 1); } @@ -508,4 +571,88 @@ mod tests { jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); assert!(jdb.exists(&foo)); } + + + #[test] + fn reopen() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let bar = H256::random(); + + let foo = { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.emplace(bar.clone(), b"bar".to_vec()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + foo + }; + + { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + } + + { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(!jdb.exists(&foo)); + } + } + + #[test] + fn reopen_remove() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let bar = H256::random(); + + let foo = { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + foo + }; + + { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(!jdb.exists(&foo)); + } + } + #[test] + fn reopen_fork() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let (foo, bar, baz) = { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + (foo, bar, baz) + }; + + { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } + } } diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index 680a6e1d0..9cd018935 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -21,6 +21,7 @@ use bytes::*; use rlp::*; use sha3::*; use hashdb::*; +use heapsize::*; use std::mem; use std::collections::HashMap; @@ -143,6 +144,11 @@ impl MemoryDB { } self.raw(key).unwrap() } + + /// Returns the size of allocated heap memory + pub fn mem_used(&self) -> usize { + self.data.heap_size_of_children() + } } static NULL_RLP_STATIC: [u8; 1] = [0x80; 1]; From 4230fdfffea3c897402eaa095a46d959928e4692 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 6 Mar 2016 22:43:21 +0100 Subject: [PATCH 403/753] More veriosning fixups. --- util/src/journaldb.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index f04affb7b..925c1c065 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -99,7 +99,7 @@ impl JournalDB { pub fn new_temp() -> JournalDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); - Self::new(DB::open_default(dir.to_str().unwrap()).unwrap()) + Self::new(dir.to_str().unwrap()) } /// Check if this database has any commits @@ -269,14 +269,15 @@ impl JournalDB { // // record new commit's details. - let batch = DBTransaction::new(); + trace!("commit: #{} ({}), end era: {:?}", now, id, end); let mut counters = self.counters.as_ref().unwrap().write().unwrap(); + let batch = DBTransaction::new(); { let mut index = 0usize; let mut last; while try!(self.backing.get({ - let mut r = RlpStream::new_list(2); + let mut r = RlpStream::new_list(3); r.append(&now); r.append(&index); r.append(&&PADDING[..]); @@ -310,6 +311,7 @@ impl JournalDB { r.append(&removes); Self::insert_keys(&inserts, &self.backing, &mut counters, &batch); try!(batch.put(&last, r.as_raw())); + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); } // apply old commits' details @@ -317,7 +319,7 @@ impl JournalDB { let mut index = 0usize; let mut last; while let Some(rlp_data) = try!(self.backing.get({ - let mut r = RlpStream::new_list(2); + let mut r = RlpStream::new_list(3); r.append(&end_era); r.append(&index); r.append(&&PADDING[..]); @@ -352,7 +354,7 @@ impl JournalDB { loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ - let mut r = RlpStream::new_list(2); + let mut r = RlpStream::new_list(3); r.append(&era); r.append(&index); r.append(&&PADDING[..]); From 0980c7130a5f299846876ec000b2fdbf8bc82c15 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 7 Mar 2016 06:58:43 +0100 Subject: [PATCH 404/753] Fix replay_keys Counters should never have an entry with zero value. --- util/src/journaldb.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 925c1c065..a008fa47e 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -191,7 +191,9 @@ impl JournalDB { // this is the first entry for this node in the journal. // it is initialised to 1 if it was already in. - counters.insert(h.clone(), if Self::is_already_in(backing, h) {1} else {0}); + if Self::is_already_in(backing, h) { + counters.insert(h.clone(), 1); + } } } From 744c4c7d8bba32c5c5e61eb8c9b32bd52498fd30 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 7 Mar 2016 07:06:55 +0100 Subject: [PATCH 405/753] JournalDB documentation --- util/src/journaldb.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 48bd94d64..1c62a9960 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -27,13 +27,37 @@ use std::env; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// and, possibly, latent-removal semantics. /// -/// If `counters` is `None`, then it behaves exactly like OverlayDB. If not it behaves +/// If `journal_overlay` is `None`, then it behaves exactly like OverlayDB. If not it behaves /// differently: /// /// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. +/// +/// There are two memory overlays: +/// - Transaction overlay contains current transaction data. It is merged with with history +/// overlay on each `commit()` +/// - History overlay contains all data inserted during the history period. When the node +/// in the overlay becomes ancient it is written to disk on `commit()` +/// +/// There is also a journal maintained in memory and on the disk as well which lists insertions +/// and removals for each commit during the history period. This is used to track +/// data nodes that go out of history scope and must be written to disk. +/// +/// Commit workflow: +/// Create a new journal record from the transaction overlay. +/// Inseart each node from the transaction overlay into the History overlay increasing reference +/// count if it is already there. Note that the reference counting is managed by `MemoryDB` +/// Clear the transaction overlay. +/// For a canonical journal record that becomes ancient inserts its insertions into the disk DB +/// For each journal record that goes out of the history scope (becomes ancient) remove its +/// insertions from the history overlay, decreasing the reference counter and removing entry if +/// if reaches zero. +/// For a canonical journal record that becomes ancient delete its removals from the disk only if +/// the removed key is not present in the history overlay. +/// Delete ancient record from memory and disk. +/// pub struct JournalDB { transaction_overlay: MemoryDB, backing: Arc, @@ -220,7 +244,6 @@ impl JournalDB { } // apply old commits' details - if let Some((end_era, canon_id)) = end { let mut canon_insertions: Vec<(H256, Bytes)> = Vec::new(); let mut canon_deletions: Vec = Vec::new(); From fd87633db662126ea95b29c1027d2d88d7565639 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 7 Mar 2016 07:57:50 +0100 Subject: [PATCH 406/753] Remove superfluous LATEST_KEY write. --- util/src/journaldb.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index a008fa47e..bb79a447c 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -336,7 +336,6 @@ impl JournalDB { try!(batch.delete(&last)); index += 1; } - try!(batch.put(&LATEST_ERA_KEY, &encode(&end_era))); trace!("JournalDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); } From 73207c23557e958761ea72b91ccdaee4ce5dd457 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 7 Mar 2016 08:01:14 +0100 Subject: [PATCH 407/753] Revert accidental beta regressions. --- util/src/journaldb.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index bb79a447c..2e78f1cce 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -351,7 +351,7 @@ impl JournalDB { fn read_counters(db: &Database) -> HashMap { let mut counters = HashMap::new(); if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val) + 1; + let mut era = decode::(&val); loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ @@ -366,10 +366,10 @@ impl JournalDB { Self::replay_keys(&inserts, db, &mut counters); index += 1; }; - if index == 0 { + if index == 0 || era == 0 { break; } - era += 1; + era -= 1; } } trace!("Recovered {} counters", counters.len()); From 4d1effb008303ef0a4ce98134a7c8658031ed2f2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 7 Mar 2016 09:10:02 +0100 Subject: [PATCH 408/753] Fix tests. --- util/src/journaldb.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 2e78f1cce..57af857a9 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -182,6 +182,7 @@ impl JournalDB { } fn replay_keys(inserts: &Vec, backing: &Database, counters: &mut HashMap) { + println!("replay_keys: inserts={:?}, counters={:?}", inserts, counters); for h in inserts { if let Some(c) = counters.get_mut(h) { // already counting. increment. @@ -192,9 +193,11 @@ impl JournalDB { // this is the first entry for this node in the journal. // it is initialised to 1 if it was already in. if Self::is_already_in(backing, h) { + println!("replace_keys: Key {} was already in!", h); counters.insert(h.clone(), 1); } } + println!("replay_keys: (end) counters={:?}", counters); } fn kill_keys(deletes: Vec, counters: &mut HashMap, batch: &DBTransaction) { @@ -361,6 +364,7 @@ impl JournalDB { r.append(&&PADDING[..]); &r.drain() }).expect("Low-level database error.") { + println!("read_counters: era={}, index={}", era, index); let rlp = Rlp::new(&rlp_data); let inserts: Vec = rlp.val_at(1); Self::replay_keys(&inserts, db, &mut counters); @@ -617,17 +621,23 @@ mod tests { // history is 1 let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + + // foo is ancient history. + jdb.insert(b"foo"); - jdb.commit(1, &b"1".sha3(), None).unwrap(); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); foo }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.remove(&foo); - jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); assert!(!jdb.exists(&foo)); } } From bcae4f6e7b5d7e0b9d2ac4a9df370d35f92d5773 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 7 Mar 2016 10:30:19 +0100 Subject: [PATCH 409/753] fixed jsonrpc reporting current block is one less than actuall, fixed #612 --- rpc/src/v1/impls/eth.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2313d5114..7113c55b1 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -312,7 +312,8 @@ impl EthFilter for EthFilterClient { None => Ok(Value::Array(vec![] as Vec)), Some(info) => match info.filter { PollFilter::Block => { - let current_number = client.chain_info().best_block_number; + // + 1, cause we want to return hashes including current block hash. + let current_number = client.chain_info().best_block_number + 1; let hashes = (info.block_number..current_number).into_iter() .map(BlockId::Number) .filter_map(|id| client.block_hash(id)) From 72016196cd654697dbfd58e7580807021fb0888a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 7 Mar 2016 10:56:39 +0100 Subject: [PATCH 410/753] Remove println!s. --- util/src/journaldb.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 57af857a9..d0d7c05ff 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -182,7 +182,7 @@ impl JournalDB { } fn replay_keys(inserts: &Vec, backing: &Database, counters: &mut HashMap) { - println!("replay_keys: inserts={:?}, counters={:?}", inserts, counters); + trace!("replay_keys: inserts={:?}, counters={:?}", inserts, counters); for h in inserts { if let Some(c) = counters.get_mut(h) { // already counting. increment. @@ -193,11 +193,11 @@ impl JournalDB { // this is the first entry for this node in the journal. // it is initialised to 1 if it was already in. if Self::is_already_in(backing, h) { - println!("replace_keys: Key {} was already in!", h); + trace!("replace_keys: Key {} was already in!", h); counters.insert(h.clone(), 1); } } - println!("replay_keys: (end) counters={:?}", counters); + trace!("replay_keys: (end) counters={:?}", counters); } fn kill_keys(deletes: Vec, counters: &mut HashMap, batch: &DBTransaction) { @@ -364,7 +364,7 @@ impl JournalDB { r.append(&&PADDING[..]); &r.drain() }).expect("Low-level database error.") { - println!("read_counters: era={}, index={}", era, index); + trace!("read_counters: era={}, index={}", era, index); let rlp = Rlp::new(&rlp_data); let inserts: Vec = rlp.val_at(1); Self::replay_keys(&inserts, db, &mut counters); From 58721475ffa68a77c23007caa6db884948e4b992 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 7 Mar 2016 11:34:07 +0100 Subject: [PATCH 411/753] Do not remove the peer immediatelly on send error --- sync/src/chain.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 63640f87f..fe1b559cd 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -575,7 +575,7 @@ impl ChainSync { pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { trace!(target: "sync", "== Connected {}", peer); if let Err(e) = self.send_status(io) { - trace!(target:"sync", "Error sending status request: {:?}", e); + warn!(target:"sync", "Error sending status request: {:?}", e); io.disable_peer(peer); } } @@ -900,9 +900,8 @@ impl ChainSync { } match sync.send(peer_id, packet_id, packet) { Err(e) => { - warn!(target:"sync", "Error sending request: {:?}", e); + debug!(target:"sync", "Error sending request: {:?}", e); sync.disable_peer(peer_id); - self.on_peer_aborting(sync, peer_id); } Ok(_) => { let mut peer = self.peers.get_mut(&peer_id).unwrap(); @@ -915,9 +914,8 @@ impl ChainSync { /// Generic packet sender fn send_packet(&mut self, sync: &mut SyncIo, peer_id: PeerId, packet_id: PacketId, packet: Bytes) { if let Err(e) = sync.send(peer_id, packet_id, packet) { - warn!(target:"sync", "Error sending packet: {:?}", e); + debug!(target:"sync", "Error sending packet: {:?}", e); sync.disable_peer(peer_id); - self.on_peer_aborting(sync, peer_id); } } /// Called when peer sends us new transactions From 3153d12bd9997f223a8a04ec40e8db21fb161663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 11:40:44 +0100 Subject: [PATCH 412/753] feature enabled when compiling without --release --- Cargo.toml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9b8ec6405..d1094a110 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,15 +12,22 @@ rustc-serialize = "0.3" docopt = "0.6" time = "0.1" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } -clippy = { version = "0.0.44", optional = true } -ethcore-util = { path = "util" } -ethcore = { path = "ethcore" } -ethsync = { path = "sync" } -ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } daemonize = "0.2" -ethcore-devtools = { path = "devtools" } number_prefix = "0.2" +clippy = { version = "0.0.44", optional = true } + +ethcore = { path = "ethcore" } +ethcore-util = { path = "util" } +ethsync = { path = "sync" } +ethcore-devtools = { path = "devtools" } +ethcore-rpc = { path = "rpc", optional = true } + +[dev-dependencies] +ethcore = { path = "ethcore", features = ["dev"]} +ethcore-util = { path = "util", features = ["dev"] } +ethsync = { path = "sync", features = ["dev"] } +ethcore-rpc = { path = "rpc", features = ["dev"]} [features] default = ["rpc"] From e83f8561041216a56a47cba39abd9ed3a0385961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 12:16:37 +0100 Subject: [PATCH 413/753] Merging chain_blocks_verified to chain_new_blocks --- sync/src/chain.rs | 78 +++++++++++++++++++++------------------ sync/src/lib.rs | 10 ++--- sync/src/tests/chain.rs | 8 ++-- sync/src/tests/helpers.rs | 4 +- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index fc0a19aba..e598c4572 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -207,7 +207,7 @@ pub struct ChainSync { /// True if common block for our and remote chain has been found have_common_block: bool, /// Last propagated block number - last_send_block_number: BlockNumber, + last_sent_block_number: BlockNumber, /// Max blocks to download ahead max_download_ahead_blocks: usize, /// Network ID @@ -236,7 +236,7 @@ impl ChainSync { last_imported_hash: None, syncing_difficulty: U256::from(0u64), have_common_block: false, - last_send_block_number: 0, + last_sent_block_number: 0, max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, transaction_queue: Mutex::new(TransactionQueue::new()), @@ -1248,26 +1248,25 @@ impl ChainSync { sent } + fn propagate_latest_blocks(&mut self, io: &mut SyncIo) { + let chain_info = io.chain().chain_info(); + if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { + let blocks = self.propagate_blocks(&chain_info, io); + let hashes = self.propagate_new_hashes(&chain_info, io); + if blocks != 0 || hashes != 0 { + trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); + } + } + self.last_sent_block_number = chain_info.best_block_number; + } + /// Maintain other peers. Send out any new blocks and transactions pub fn maintain_sync(&mut self, io: &mut SyncIo) { self.check_resume(io); } - /// should be called once chain has new block, triggers the latest block propagation - pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) { - let chain = io.chain().chain_info(); - if (((chain.best_block_number as i64) - (self.last_send_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let blocks = self.propagate_blocks(&chain, io); - let hashes = self.propagate_new_hashes(&chain, io); - if blocks != 0 || hashes != 0 { - trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); - } - } - self.last_send_block_number = chain.best_block_number; - } - - /// called when block is imported to chain, updates transactions queue - pub fn chain_new_blocks(&mut self, io: &SyncIo, good: &[H256], bad: &[H256], _retracted: &[H256]) { + /// called when block is imported to chain, updates transactions queue and propagates the blocks + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, good: &[H256], bad: &[H256], _retracted: &[H256]) { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockId::Hash(hash.clone())) @@ -1278,24 +1277,31 @@ impl ChainSync { } - let chain = io.chain(); - let good = good.par_iter().map(|h| fetch_transactions(chain, h)); - let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); + { + let chain = io.chain(); + let good = good.par_iter().map(|h| fetch_transactions(chain, h)); + let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); - good.for_each(|txs| { - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); - transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); - }); - bad.for_each(|txs| { - // populate sender - for tx in &txs { - let _sender = tx.sender(); - } - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(txs, |a| chain.nonce(a)); - }); + good.for_each(|txs| { + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); + transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); + }); + bad.for_each(|txs| { + // populate sender + for tx in &txs { + let _sender = tx.sender(); + } + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.add_all(txs, |a| chain.nonce(a)); + }); + } + + // Propagate latests blocks + self.propagate_latest_blocks(io); + // TODO [todr] propagate transactions? } + } #[cfg(test)] @@ -1634,13 +1640,13 @@ mod tests { let retracted_blocks = vec![client.block_hash_delta_minus(1)]; let mut queue = VecDeque::new(); - let io = TestIo::new(&mut client, &mut queue, None); + let mut io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&io, &[], &good_blocks, &[]); + sync.chain_new_blocks(&mut io, &[], &good_blocks, &[]); assert_eq!(sync.transaction_queue.lock().unwrap().status().future, 0); assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); - sync.chain_new_blocks(&io, &good_blocks, &retracted_blocks, &[]); + sync.chain_new_blocks(&mut io, &good_blocks, &retracted_blocks, &[]); // then let status = sync.transaction_queue.lock().unwrap().status(); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 8a30385a2..b5869642c 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -154,13 +154,11 @@ impl NetworkProtocolHandler for EthSync { fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { - SyncMessage::BlockVerified => { - self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); - }, SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted } => { - let sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&sync_io, good, bad, retracted); - } + let mut sync_io = NetSyncIo::new(io, self.chain.deref()); + self.sync.write().unwrap().chain_new_blocks(&mut sync_io, good, bad, retracted); + }, + _ => {/* Ignore other messages */}, } } } diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 58f50916e..855aa79a6 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -129,8 +129,8 @@ fn propagate_hashes() { net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.trigger_block_verified(0); //first event just sets the marker - net.trigger_block_verified(0); + net.trigger_chain_new_blocks(0); //first event just sets the marker + net.trigger_chain_new_blocks(0); // 5 peers to sync assert_eq!(5, net.peer(0).queue.len()); @@ -154,8 +154,8 @@ fn propagate_blocks() { net.sync(); net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); - net.trigger_block_verified(0); //first event just sets the marker - net.trigger_block_verified(0); + net.trigger_chain_new_blocks(0); //first event just sets the marker + net.trigger_chain_new_blocks(0); assert!(!net.peer(0).queue.is_empty()); // NEW_BLOCK_PACKET diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 5b53ad90b..d01dba0b2 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -455,8 +455,8 @@ impl TestNet { self.peers.iter().all(|p| p.queue.is_empty()) } - pub fn trigger_block_verified(&mut self, peer_id: usize) { + pub fn trigger_chain_new_blocks(&mut self, peer_id: usize) { let mut peer = self.peer_mut(peer_id); - peer.sync.chain_blocks_verified(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None)); + peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[]); } } From ec3698066b8dd3f5a061498a9203644511cf8e21 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 7 Mar 2016 12:21:11 +0100 Subject: [PATCH 414/753] Normal CLI options with geth. Support node identity. Support fine-grained JSONRPC API enabling. --- ethcore/src/client.rs | 3 + parity/main.rs | 130 ++++++++++++++++++++++++++++++------------ 2 files changed, 96 insertions(+), 37 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 9688cc527..8471666aa 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -87,6 +87,8 @@ pub struct ClientConfig { pub blockchain: BlockChainConfig, /// Prefer journal rather than archive. pub prefer_journal: bool, + /// The name of the client instance. + pub name: String, } impl Default for ClientConfig { @@ -95,6 +97,7 @@ impl Default for ClientConfig { queue: Default::default(), blockchain: Default::default(), prefer_journal: false, + name: Default::default(), } } } diff --git a/parity/main.rs b/parity/main.rs index 605fb315d..43b0504f1 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -53,6 +53,16 @@ use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; +fn die_with_message(msg: &str) -> ! { + println!("ERROR: {}", msg); + exit(1); +} + +#[macro_export] +macro_rules! die { + ($($arg:tt)*) => (die_with_message(&format!("{}", format_args!($($arg)*)))); +} + const USAGE: &'static str = r#" Parity. Ethereum Client. By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf. @@ -62,13 +72,16 @@ Usage: parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] -Options: +Protocol Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file - or frontier, mainnet, morden, or testnet [default: frontier]. + or olympic, frontier, homestead, mainnet, morden, or testnet [default: homestead]. + --testnet Equivalent to --chain testnet (geth-compatible). + --networkid INDEX Override the network identifier from the chain we are on. --archive Client should not prune the state/storage trie. - -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] - --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] + -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] + --identity NAME Specify your node's name. +Networking Options: --no-bootstrap Don't bother trying to connect to any nodes initially. --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect. @@ -78,18 +91,32 @@ Options: --no-upnp Disable trying to figure out the correct public adderss over UPnP. --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. +API and Console Options: + -j --jsonrpc Enable the JSON-RPC API sever. + --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API server [default: 127.0.0.1]. + --jsonrpc-port PORT Specify the port portion of the JSONRPC API server [default: 8545]. + --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. + --jsonrpc-apis APIS Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited + list of API name. Possible name are web3, eth and net. [default: web3,eth,net]. + --rpc Equivalent to --jsonrpc (geth-compatible). + --rpcaddr HOST Equivalent to --jsonrpc-addr HOST (geth-compatible). + --rpcport PORT Equivalent to --jsonrpc-port PORT (geth-compatible). + --rpcapi APIS Equivalent to --jsonrpc-apis APIS (geth-compatible). + --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). + +Sealing/Mining Options: + --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards + from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. + --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. + +Memory Footprint Options: --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. --queue-max-size BYTES Specify the maximum size of memory to use for block queue [default: 52428800]. + --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with + other cache options (geth-compatible). - -j --jsonrpc Enable the JSON-RPC API sever. - --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. - --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. - - --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards - from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. - --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. - +Miscellaneous Options: -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. @@ -101,14 +128,18 @@ struct Args { arg_pid_file: String, arg_enode: Vec, flag_chain: String, + flag_testnet: bool, flag_db_path: String, + flag_networkid: Option, + flag_identity: String, + flag_cache: Option, flag_keys_path: String, flag_archive: bool, flag_no_bootstrap: bool, flag_listen_address: String, flag_public_address: Option, flag_address: Option, - flag_peers: u32, + flag_peers: usize, flag_no_discovery: bool, flag_no_upnp: bool, flag_node_key: Option, @@ -116,8 +147,15 @@ struct Args { flag_cache_max_size: usize, flag_queue_max_size: usize, flag_jsonrpc: bool, - flag_jsonrpc_url: String, + flag_jsonrpc_addr: String, + flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, + flag_jsonrpc_apis: String, + flag_rpc: bool, + flag_rpcaddr: Option, + flag_rpcport: Option, + flag_rpccorsdomain: Option, + flag_rpcapi: Option, flag_logging: Option, flag_version: bool, flag_author: String, @@ -151,14 +189,23 @@ fn setup_log(init: &Option) { } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_domain: &str) { +fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) { use rpc::v1::*; let mut server = rpc::HttpServer::new(1); - server.add_delegate(Web3Client::new().to_delegate()); - server.add_delegate(EthClient::new(&client, &sync).to_delegate()); - server.add_delegate(EthFilterClient::new(&client).to_delegate()); - server.add_delegate(NetClient::new(&sync).to_delegate()); + for api in apis.into_iter() { + match api { + "web3" => server.add_delegate(Web3Client::new().to_delegate()), + "net" => server.add_delegate(NetClient::new(&sync).to_delegate()), + "eth" => { + server.add_delegate(EthClient::new(&client, &sync).to_delegate()); + server.add_delegate(EthFilterClient::new(&client).to_delegate()); + } + _ => { + die!("{}: Invalid API name to be enabled.", api); + } + } + } server.start_async(url, cors_domain); } @@ -179,16 +226,6 @@ By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf.\ ", version()); } -fn die_with_message(msg: &str) -> ! { - println!("ERROR: {}", msg); - exit(1); -} - -#[macro_export] -macro_rules! die { - ($($arg:tt)*) => (die_with_message(&format!("{}", format_args!($($arg)*)))); -} - struct Configuration { args: Args } @@ -221,8 +258,11 @@ impl Configuration { } fn spec(&self) -> Spec { + if self.args.flag_testnet { + return ethereum::new_morden(); + } match self.args.flag_chain.as_ref() { - "frontier" | "mainnet" => ethereum::new_frontier(), + "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(), "morden" | "testnet" => ethereum::new_morden(), "olympic" => ethereum::new_olympic(), f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| die!("{}: Couldn't read chain specification file. Sure it exists?", f)).as_ref()), @@ -276,7 +316,7 @@ impl Configuration { ret.public_address = public; ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3())); ret.discovery_enabled = !self.args.flag_no_discovery; - ret.ideal_peers = self.args.flag_peers; + ret.ideal_peers = self.args.flag_peers as u32; let mut net_path = PathBuf::from(&self.path()); net_path.push("network"); ret.config_path = Some(net_path.to_str().unwrap().to_owned()); @@ -307,13 +347,22 @@ impl Configuration { let spec = self.spec(); let net_settings = self.net_settings(&spec); let mut sync_config = SyncConfig::default(); - sync_config.network_id = spec.network_id(); + sync_config.network_id = self.args.flag_networkid.as_ref().map(|id| U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --networkid", id))).unwrap_or(spec.network_id()); // Build client let mut client_config = ClientConfig::default(); - client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; - client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; + match self.args.flag_cache { + Some(mb) => { + client_config.blockchain.max_cache_size = mb * 1024 * 1024; + client_config.blockchain.pref_cache_size = client_config.blockchain.max_cache_size / 2; + } + None => { + client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; + client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; + } + } client_config.prefer_journal = !self.args.flag_archive; + client_config.name = self.args.flag_identity.clone(); client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let client = service.client().clone(); @@ -324,9 +373,16 @@ impl Configuration { let sync = EthSync::register(service.network(), sync_config, client); // Setup rpc - if self.args.flag_jsonrpc { - setup_rpc_server(service.client(), sync.clone(), &self.args.flag_jsonrpc_url, &self.args.flag_jsonrpc_cors); - SocketAddr::from_str(&self.args.flag_jsonrpc_url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen address given with --jsonrpc-url. Should be of the form 'IP:port'.", self.args.flag_jsonrpc_url)); + if self.args.flag_jsonrpc || self.args.flag_rpc { + let url = format!("{}:{}", + self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_addr), + self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) + ); + SocketAddr::from_str(&url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen host/port given.", url)); + let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); + // TODO: use this as the API list. + let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); + setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect()); } // Register IO handler From cbc2c0cf0c76bf12361641c6825e21e82bdec7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 14:33:00 +0100 Subject: [PATCH 415/753] Fixing clippy warnings. When building on nightly it is required to enable clippy --- Cargo.lock | 4 +++ Cargo.toml | 13 ++++++--- build.rs | 25 ++++++++++++++++ cargo.sh | 2 ++ ethcore/Cargo.toml | 6 +++- ethcore/build.rs | 25 ++++++++++++++++ ethcore/src/basic_types.rs | 2 +- ethcore/src/block.rs | 4 +-- ethcore/src/block_queue.rs | 4 +-- ethcore/src/blockchain/blockchain.rs | 4 +-- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/evm/interpreter.rs | 6 ++-- ethcore/src/evm/tests.rs | 11 ++++--- ethcore/src/externalities.rs | 6 ++-- ethcore/src/lib.rs | 10 +++---- ethcore/src/service.rs | 9 +++--- ethcore/src/spec.rs | 10 +++---- ethcore/src/state.rs | 2 +- ethcore/src/transaction.rs | 2 +- ethcore/src/verification/mod.rs | 2 ++ hook.sh | 2 +- parity/main.rs | 6 ++-- rpc/Cargo.toml | 3 +- rpc/build.rs | 23 +++++++++++++++ sync/Cargo.toml | 6 +++- sync/build.rs | 25 ++++++++++++++++ sync/src/chain.rs | 7 +++-- sync/src/lib.rs | 6 ++-- sync/src/range_collection.rs | 2 +- util/Cargo.toml | 2 +- util/bigint/src/uint.rs | 6 ++-- util/build.rs | 21 ++++++++++++++ util/src/hash.rs | 4 +-- util/src/journaldb.rs | 43 +++++++++++++++------------- util/src/kvdb.rs | 3 +- util/src/lib.rs | 12 ++++---- util/src/network/discovery.rs | 22 +++++++------- util/src/network/host.rs | 4 +-- util/src/panics.rs | 2 +- util/src/trie/triedb.rs | 18 ++++++------ util/src/trie/triedbmut.rs | 36 +++++++++++------------ 41 files changed, 272 insertions(+), 130 deletions(-) create mode 100644 build.rs create mode 100755 cargo.sh create mode 100644 ethcore/build.rs create mode 100644 sync/build.rs diff --git a/Cargo.lock b/Cargo.lock index 55ed996ed..61f152f69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,6 +16,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,6 +210,7 @@ dependencies = [ "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -232,6 +234,7 @@ dependencies = [ "jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -286,6 +289,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index d1094a110..d8e05bb20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,10 @@ name = "parity" version = "0.9.99" license = "GPL-3.0" authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +rustc_version = "0.1" [dependencies] log = "0.3" @@ -24,17 +28,18 @@ ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } [dev-dependencies] -ethcore = { path = "ethcore", features = ["dev"]} +ethcore = { path = "ethcore", features = ["dev"] } ethcore-util = { path = "util", features = ["dev"] } ethsync = { path = "sync", features = ["dev"] } -ethcore-rpc = { path = "rpc", features = ["dev"]} +ethcore-rpc = { path = "rpc", features = ["dev"] } [features] default = ["rpc"] rpc = ["ethcore-rpc"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] +dev = ["ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] +dev-clippy = ["clippy", "ethcore/clippy", "ethcore-util/clippy", "ethsync/clippy", "ethcore-rpc/clippy"] travis-beta = ["ethcore/json-tests"] -travis-nightly = ["ethcore/json-tests", "dev"] +travis-nightly = ["ethcore/json-tests", "clippy", "dev"] [[bin]] path = "parity/main.rs" diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..41b9a1b3e --- /dev/null +++ b/build.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } +} diff --git a/cargo.sh b/cargo.sh new file mode 100755 index 000000000..6870ab385 --- /dev/null +++ b/cargo.sh @@ -0,0 +1,2 @@ +#!/bin/sh +cargo "$@" --features dev-clippy diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index c3a3d32dc..fbfe175d7 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -5,6 +5,10 @@ license = "GPL-3.0" name = "ethcore" version = "0.9.99" authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +rustc_version = "0.1" [dependencies] log = "0.3" @@ -27,5 +31,5 @@ jit = ["evmjit"] evm-debug = [] json-tests = [] test-heavy = [] -dev = ["clippy"] +dev = [] default = [] diff --git a/ethcore/build.rs b/ethcore/build.rs new file mode 100644 index 000000000..41b9a1b3e --- /dev/null +++ b/ethcore/build.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } +} diff --git a/ethcore/src/basic_types.rs b/ethcore/src/basic_types.rs index 5f6515c0d..9cba8b3a0 100644 --- a/ethcore/src/basic_types.rs +++ b/ethcore/src/basic_types.rs @@ -24,7 +24,7 @@ pub type LogBloom = H2048; /// Constant 2048-bit datum for 0. Often used as a default. pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); -#[cfg_attr(feature="dev", allow(enum_variant_names))] +#[cfg_attr(all(nightly, feature="dev"), allow(enum_variant_names))] /// Semantic boolean for when a seal/signature is included. pub enum Seal { /// The seal/signature is included. diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 68f647e37..b3894db94 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -16,7 +16,7 @@ //! Blockchain block. -#![cfg_attr(feature="dev", allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> +#![cfg_attr(all(nightly, feature="dev"), allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> use common::*; use engine::*; @@ -274,7 +274,7 @@ impl<'x> OpenBlock<'x> { s.block.base.header.note_dirty(); ClosedBlock { - block: s.block, + block: s.block, uncle_bytes: uncle_bytes, } } diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 490a17995..de6802a4f 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -121,7 +121,7 @@ struct QueueSignal { } impl QueueSignal { - #[cfg_attr(feature="dev", allow(bool_comparison))] + #[cfg_attr(all(nightly, feature="dev"), allow(bool_comparison))] fn set(&self) { if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false { self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message"); @@ -385,7 +385,7 @@ impl BlockQueue { } } - pub fn collect_garbage(&self) { + pub fn collect_garbage(&self) { { let mut verification = self.verification.lock().unwrap(); verification.unverified.shrink_to_fit(); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index e529f50af..d7c9d7975 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -884,7 +884,7 @@ mod tests { } #[test] - #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] fn test_find_uncles() { let mut canon_chain = ChainGenerator::default(); let mut finalizer = BlockFinalizer::default(); @@ -922,7 +922,7 @@ mod tests { } #[test] - #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] fn test_small_fork() { let mut canon_chain = ChainGenerator::default(); let mut finalizer = BlockFinalizer::default(); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index f9810b964..b0c0e4a9f 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -202,7 +202,7 @@ impl Engine for Ethash { } } -#[cfg_attr(feature="dev", allow(wrong_self_convention))] // to_ethash should take self +#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] // to_ethash should take self impl Ethash { fn calculate_difficuty(&self, header: &Header, parent: &Header) -> U256 { const EXP_DIFF_PERIOD: u64 = 100000; diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index 7491321cb..fb8d19357 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -243,7 +243,7 @@ struct CodeReader<'a> { code: &'a Bytes } -#[cfg_attr(feature="dev", allow(len_without_is_empty))] +#[cfg_attr(all(nightly, feature="dev"), allow(len_without_is_empty))] impl<'a> CodeReader<'a> { /// Get `no_of_bytes` from code and convert to U256. Move PC fn read(&mut self, no_of_bytes: usize) -> U256 { @@ -258,7 +258,7 @@ impl<'a> CodeReader<'a> { } } -#[cfg_attr(feature="dev", allow(enum_variant_names))] +#[cfg_attr(all(nightly, feature="dev"), allow(enum_variant_names))] enum InstructionCost { Gas(U256), GasMem(U256, U256), @@ -347,7 +347,7 @@ impl evm::Evm for Interpreter { } impl Interpreter { - #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] fn get_gas_cost_mem(&self, ext: &evm::Ext, instruction: Instruction, diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 9d4dd3bc4..dc84a9a05 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -25,9 +25,8 @@ struct FakeLogEntry { } #[derive(PartialEq, Eq, Hash, Debug)] -#[cfg_attr(feature="dev", allow(enum_variant_names))] // Common prefix is C ;) enum FakeCallType { - CALL, CREATE + Call, Create } #[derive(PartialEq, Eq, Hash, Debug)] @@ -94,7 +93,7 @@ impl Ext for FakeExt { fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { self.calls.insert(FakeCall { - call_type: FakeCallType::CREATE, + call_type: FakeCallType::Create, gas: *gas, sender_address: None, receive_address: None, @@ -115,7 +114,7 @@ impl Ext for FakeExt { _output: &mut [u8]) -> MessageCallResult { self.calls.insert(FakeCall { - call_type: FakeCallType::CALL, + call_type: FakeCallType::Call, gas: *gas, sender_address: Some(sender_address.clone()), receive_address: Some(receive_address.clone()), @@ -909,7 +908,7 @@ fn test_calls(factory: super::Factory) { }; assert_set_contains(&ext.calls, &FakeCall { - call_type: FakeCallType::CALL, + call_type: FakeCallType::Call, gas: U256::from(2556), sender_address: Some(address.clone()), receive_address: Some(code_address.clone()), @@ -918,7 +917,7 @@ fn test_calls(factory: super::Factory) { code_address: Some(code_address.clone()) }); assert_set_contains(&ext.calls, &FakeCall { - call_type: FakeCallType::CALL, + call_type: FakeCallType::Call, gas: U256::from(2556), sender_address: Some(address.clone()), receive_address: Some(address.clone()), diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index beb8d62a1..a1f5763ea 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -188,7 +188,7 @@ impl<'a> Ext for Externalities<'a> { self.state.code(address).unwrap_or_else(|| vec![]) } - #[cfg_attr(feature="dev", allow(match_ref_pats))] + #[cfg_attr(all(nightly, feature="dev"), allow(match_ref_pats))] fn ret(&mut self, gas: &U256, data: &[u8]) -> Result { match &mut self.output { &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { @@ -226,9 +226,9 @@ impl<'a> Ext for Externalities<'a> { fn log(&mut self, topics: Vec, data: &[u8]) { let address = self.origin_info.address.clone(); - self.substate.logs.push(LogEntry { + self.substate.logs.push(LogEntry { address: address, - topics: topics, + topics: topics, data: data.to_vec() }); } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 938da02a0..469364eb3 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -15,16 +15,16 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(feature="dev", plugin(clippy))] +#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] +#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] // Clippy config // TODO [todr] not really sure -#![cfg_attr(feature="dev", allow(needless_range_loop))] +#![cfg_attr(all(nightly, feature="dev"), allow(needless_range_loop))] // Shorter than if-else -#![cfg_attr(feature="dev", allow(match_bool))] +#![cfg_attr(all(nightly, feature="dev"), allow(match_bool))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(feature="dev", allow(clone_on_copy))] +#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] //! Ethcore library //! diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 756d02407..33dca8de7 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -115,12 +115,11 @@ impl IoHandler for ClientIoHandler { } } - #[cfg_attr(feature="dev", allow(match_ref_pats))] - #[cfg_attr(feature="dev", allow(single_match))] + #[cfg_attr(all(nightly, feature="dev"), allow(single_match))] fn message(&self, io: &IoContext, net_message: &NetSyncMessage) { - if let &UserMessage(ref message) = net_message { - match message { - &SyncMessage::BlockVerified => { + if let UserMessage(ref message) = *net_message { + match *message { + SyncMessage::BlockVerified => { self.client.import_verified_blocks(&io.channel()); }, _ => {}, // ignore other messages diff --git a/ethcore/src/spec.rs b/ethcore/src/spec.rs index 38a0dda53..774024351 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec.rs @@ -99,7 +99,7 @@ pub struct Spec { genesis_state: PodState, } -#[cfg_attr(feature="dev", allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) +#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) impl Spec { /// Convert this object into a boxed Engine of the right underlying type. // TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead. @@ -136,7 +136,7 @@ impl Spec { uncles_hash: RlpStream::new_list(0).out().sha3(), extra_data: self.extra_data.clone(), state_root: self.state_root().clone(), - receipts_root: self.receipts_root.clone(), + receipts_root: self.receipts_root.clone(), log_bloom: H2048::new().clone(), gas_used: self.gas_used.clone(), gas_limit: self.gas_limit.clone(), @@ -182,7 +182,7 @@ impl Spec { ) } }; - + self.parent_hash = H256::from_json(&genesis["parentHash"]); self.transactions_root = genesis.find("transactionsTrie").and_then(|_| Some(H256::from_json(&genesis["transactionsTrie"]))).unwrap_or(SHA3_NULL_RLP.clone()); self.receipts_root = genesis.find("receiptTrie").and_then(|_| Some(H256::from_json(&genesis["receiptTrie"]))).unwrap_or(SHA3_NULL_RLP.clone()); @@ -249,7 +249,7 @@ impl FromJson for Spec { ) } }; - + Spec { name: json.find("name").map_or("unknown", |j| j.as_string().unwrap()).to_owned(), engine_name: json["engineName"].as_string().unwrap().to_owned(), @@ -278,7 +278,7 @@ impl Spec { /// Ensure that the given state DB has the trie nodes in for the genesis state. pub fn ensure_db_good(&self, db: &mut HashDB) -> bool { if !db.contains(&self.state_root()) { - let mut root = H256::new(); + let mut root = H256::new(); { let mut t = SecTrieDBMut::new(db, &mut root); for (address, account) in self.genesis_state.get().iter() { diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index c13678c38..7c1064abf 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -224,7 +224,7 @@ impl State { /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. - #[cfg_attr(feature="dev", allow(match_ref_pats))] + #[cfg_attr(all(nightly, feature="dev"), allow(match_ref_pats))] pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { // first, commit the sub trees. // TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index a51824494..733e5ac6b 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -80,7 +80,7 @@ impl Transaction { } impl FromJson for SignedTransaction { - #[cfg_attr(feature="dev", allow(single_char_pattern))] + #[cfg_attr(all(nightly, feature="dev"), allow(single_char_pattern))] fn from_json(json: &Json) -> SignedTransaction { let t = Transaction { nonce: xjson!(&json["nonce"]), diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs index 260121989..fe1f406cc 100644 --- a/ethcore/src/verification/mod.rs +++ b/ethcore/src/verification/mod.rs @@ -17,9 +17,11 @@ pub mod verification; pub mod verifier; mod canon_verifier; +#[cfg(test)] mod noop_verifier; pub use self::verification::*; pub use self::verifier::Verifier; pub use self::canon_verifier::CanonVerifier; +#[cfg(test)] pub use self::noop_verifier::NoopVerifier; diff --git a/hook.sh b/hook.sh index 106ffe4f0..354fddd5d 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,3 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --features dev" > ./.git/hooks/pre-push +echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --features dev-clippy" > ./.git/hooks/pre-push chmod +x ./.git/hooks/pre-push diff --git a/parity/main.rs b/parity/main.rs index 605fb315d..4055fcf46 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -17,8 +17,8 @@ //! Ethcore client application. #![warn(missing_docs)] -#![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(feature="dev", plugin(clippy))] +#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] +#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] extern crate docopt; extern crate rustc_serialize; extern crate ethcore_util as util; @@ -246,7 +246,7 @@ impl Configuration { } } - #[cfg_attr(feature="dev", allow(useless_format))] + #[cfg_attr(all(nightly, feature="dev"), allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { let mut listen_address = None; let mut public_address = None; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index bfdf8f2d3..07c0eb85d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -26,8 +26,9 @@ serde_macros = { version = "0.7.0", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } syntex = "0.29.0" +rustc_version = "0.1" [features] default = ["serde_codegen"] nightly = ["serde_macros"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev"] +dev = ["ethcore/dev", "ethcore-util/dev", "ethsync/dev"] diff --git a/rpc/build.rs b/rpc/build.rs index b5adeaba1..3806f6fe5 100644 --- a/rpc/build.rs +++ b/rpc/build.rs @@ -1,3 +1,23 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; + #[cfg(not(feature = "serde_macros"))] mod inner { extern crate syntex; @@ -26,4 +46,7 @@ mod inner { fn main() { inner::main(); + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index f10a772e3..fd4b9c46f 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -4,9 +4,13 @@ name = "ethsync" version = "0.9.99" license = "GPL-3.0" authors = ["Ethcore . + +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } +} diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 63640f87f..0feae01b0 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -268,7 +268,7 @@ impl ChainSync { } - #[cfg_attr(feature="dev", allow(for_kv_map))] // Because it's not possible to get `values_mut()` + #[cfg_attr(all(nightly, feature="dev"), allow(for_kv_map))] // Because it's not possible to get `values_mut()` /// Rest sync. Clear all downloaded data but keep the queue fn reset(&mut self) { self.downloading_headers.clear(); @@ -335,7 +335,7 @@ impl ChainSync { Ok(()) } - #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] /// Called by peer once it has new block headers during sync fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders); @@ -462,6 +462,7 @@ impl ChainSync { } /// Called by peer once it has new block bodies + #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { let block_rlp = try!(r.at(0)); let header_rlp = try!(block_rlp.at(0)); @@ -484,7 +485,7 @@ impl ChainSync { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { - if self.current_base_block() < header.number { + if self.current_base_block() < header.number { self.last_imported_block = Some(header.number); self.remove_downloaded_blocks(header.number); } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 74541660d..3ce33e31f 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -15,11 +15,11 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(feature="dev", plugin(clippy))] +#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] +#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(feature="dev", allow(clone_on_copy))] +#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] //! Blockchain sync module //! Implements ethereum protocol version 63 as specified here: diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index dc2f4e446..dad732fe8 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -207,7 +207,7 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } #[test] -#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] +#[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] fn test_range() { use std::cmp::{Ordering}; diff --git a/util/Cargo.toml b/util/Cargo.toml index 9c5cb3fe3..0ce27ec2b 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -40,7 +40,7 @@ chrono = "0.2" [features] default = [] -dev = ["clippy"] +dev = [] [build-dependencies] vergen = "*" diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index bd57e9d6d..959df0944 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -1103,7 +1103,7 @@ macro_rules! construct_uint { } } - #[cfg_attr(feature="dev", allow(derive_hash_xor_eq))] // We are pretty sure it's ok. + #[cfg_attr(all(nightly, feature="dev"), allow(derive_hash_xor_eq))] // We are pretty sure it's ok. impl Hash for $name { fn hash(&self, state: &mut H) where H: Hasher { unsafe { state.write(::std::slice::from_raw_parts(self.0.as_ptr() as *mut u8, self.0.len() * 8)); } @@ -1485,7 +1485,7 @@ mod tests { } #[test] - #[cfg_attr(feature="dev", allow(eq_op))] + #[cfg_attr(all(nightly, feature="dev"), allow(eq_op))] pub fn uint256_comp_test() { let small = U256([10u64, 0, 0, 0]); let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); @@ -2032,7 +2032,7 @@ mod tests { #[test] - #[cfg_attr(feature = "dev", allow(cyclomatic_complexity))] + #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] fn u256_multi_full_mul() { let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0])); assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result); diff --git a/util/build.rs b/util/build.rs index eed080e29..0b9b233e0 100644 --- a/util/build.rs +++ b/util/build.rs @@ -1,7 +1,28 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate rustc_version; extern crate vergen; use vergen::*; +use rustc_version::{version_meta, Channel}; fn main() { vergen(OutputFns::all()).unwrap(); + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } } diff --git a/util/src/hash.rs b/util/src/hash.rs index 73fa33b47..4eb96b53e 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -305,7 +305,7 @@ macro_rules! impl_hash { } impl Copy for $from {} - #[cfg_attr(feature="dev", allow(expl_impl_clone_on_copy))] + #[cfg_attr(all(nightly, feature="dev"), allow(expl_impl_clone_on_copy))] impl Clone for $from { fn clone(&self) -> $from { unsafe { @@ -637,7 +637,7 @@ mod tests { use std::str::FromStr; #[test] - #[cfg_attr(feature="dev", allow(eq_op))] + #[cfg_attr(all(nightly, feature="dev"), allow(eq_op))] fn hash() { let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 57af857a9..3228f2201 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -27,7 +27,7 @@ use std::env; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// -/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to +/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. @@ -158,7 +158,7 @@ impl JournalDB { backing.get(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?").is_some() } - fn insert_keys(inserts: &Vec<(H256, Bytes)>, backing: &Database, counters: &mut HashMap, batch: &DBTransaction) { + fn insert_keys(inserts: &[(H256, Bytes)], backing: &Database, counters: &mut HashMap, batch: &DBTransaction) { for &(ref h, ref d) in inserts { if let Some(c) = counters.get_mut(h) { // already counting. increment. @@ -181,7 +181,7 @@ impl JournalDB { } } - fn replay_keys(inserts: &Vec, backing: &Database, counters: &mut HashMap) { + fn replay_keys(inserts: &[H256], backing: &Database, counters: &mut HashMap) { println!("replay_keys: inserts={:?}, counters={:?}", inserts, counters); for h in inserts { if let Some(c) = counters.get_mut(h) { @@ -211,12 +211,12 @@ impl JournalDB { n = Some(*c); } } - match &n { - &Some(i) if i == 1 => { + match n { + Some(i) if i == 1 => { counters.remove(&h); Self::reset_already_in(batch, &h); } - &None => { + None => { // Gets removed when moving from 1 to 0 additional refs. Should never be here at 0 additional refs. //assert!(!Self::is_already_in(db, &h)); batch.delete(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?"); @@ -229,7 +229,7 @@ impl JournalDB { /// Commit all recent insert operations and historical removals from the old era /// to the backing database. fn commit_with_counters(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: + // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, n] => [ ... ] @@ -242,12 +242,12 @@ impl JournalDB { // By the time comes to remove a tuple from the queue (i.e. then the era passes from recent history // into ancient history) then only one commit from the tuple is considered canonical. This commit // is kept in the main backing database, whereas any others from the same era are reverted. - // + // // It is possible that a key, properly available in the backing database be deleted and re-inserted // in the recent history queue, yet have both operations in commits that are eventually non-canonical. // To avoid the original, and still required, key from being deleted, we maintain a reference count // which includes an original key, if any. - // + // // The semantics of the `counter` are: // insert key k: // counter already contains k: count += 1 @@ -255,7 +255,7 @@ impl JournalDB { // backing db contains k: count = 1 // backing db doesn't contain k: insert into backing db, count = 0 // delete key k: - // counter contains k (count is asserted to be non-zero): + // counter contains k (count is asserted to be non-zero): // count > 1: counter -= 1 // count == 1: remove counter // count == 0: remove key from backing db @@ -274,7 +274,7 @@ impl JournalDB { // // record new commit's details. - trace!("commit: #{} ({}), end era: {:?}", now, id, end); + trace!("commit: #{} ({}), end era: {:?}", now, id, end); let mut counters = self.counters.as_ref().unwrap().write().unwrap(); let batch = DBTransaction::new(); { @@ -295,7 +295,7 @@ impl JournalDB { let drained = self.overlay.drain(); let removes: Vec = drained .iter() - .filter_map(|(ref k, &(_, ref c))| if *c < 0 {Some(k.clone())} else {None}).cloned() + .filter_map(|(k, &(_, c))| if c < 0 {Some(k.clone())} else {None}) .collect(); let inserts: Vec<(H256, Bytes)> = drained .into_iter() @@ -382,12 +382,15 @@ impl JournalDB { /// Returns heap memory size used pub fn mem_used(&self) -> usize { - self.overlay.mem_used() + match &self.counters { &Some(ref c) => c.read().unwrap().heap_size_of_children(), &None => 0 } + self.overlay.mem_used() + match self.counters { + Some(ref c) => c.read().unwrap().heap_size_of_children(), + None => 0 + } } } impl HashDB for JournalDB { - fn keys(&self) -> HashMap { + fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter() { let h = H256::from_slice(key.deref()); @@ -401,7 +404,7 @@ impl HashDB for JournalDB { ret } - fn lookup(&self, key: &H256) -> Option<&[u8]> { + fn lookup(&self, key: &H256) -> Option<&[u8]> { let k = self.overlay.raw(key); match k { Some(&(ref d, rc)) if rc > 0 => Some(d), @@ -416,18 +419,18 @@ impl HashDB for JournalDB { } } - fn exists(&self, key: &H256) -> bool { + fn exists(&self, key: &H256) -> bool { self.lookup(key).is_some() } - fn insert(&mut self, value: &[u8]) -> H256 { + fn insert(&mut self, value: &[u8]) -> H256 { self.overlay.insert(value) } fn emplace(&mut self, key: H256, value: Bytes) { - self.overlay.emplace(key, value); + self.overlay.emplace(key, value); } - fn kill(&mut self, key: &H256) { - self.overlay.kill(key); + fn kill(&mut self, key: &H256) { + self.overlay.kill(key); } } diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index 43a9fc532..a2fa2215a 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -55,8 +55,7 @@ pub struct DatabaseIterator<'a> { impl<'a> Iterator for DatabaseIterator<'a> { type Item = (Box<[u8]>, Box<[u8]>); - #[cfg_attr(feature="dev", allow(type_complexity))] - fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> { + fn next(&mut self) -> Option { self.iter.next() } } diff --git a/util/src/lib.rs b/util/src/lib.rs index a50ba8da4..59d66a325 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -15,18 +15,18 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(feature="dev", plugin(clippy))] +#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] +#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] // Clippy settings // TODO [todr] not really sure -#![cfg_attr(feature="dev", allow(needless_range_loop))] +#![cfg_attr(all(nightly, feature="dev"), allow(needless_range_loop))] // Shorter than if-else -#![cfg_attr(feature="dev", allow(match_bool))] +#![cfg_attr(all(nightly, feature="dev"), allow(match_bool))] // We use that to be more explicit about handled cases -#![cfg_attr(feature="dev", allow(match_same_arms))] +#![cfg_attr(all(nightly, feature="dev"), allow(match_same_arms))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(feature="dev", allow(clone_on_copy))] +#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] //! Ethcore-util library //! diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index e52d5d25f..644af22af 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -113,14 +113,14 @@ impl Discovery { } /// Add a new node to discovery table. Pings the node. - pub fn add_node(&mut self, e: NodeEntry) { + pub fn add_node(&mut self, e: NodeEntry) { let endpoint = e.endpoint.clone(); self.update_node(e); self.ping(&endpoint); } /// Add a list of known nodes to the table. - pub fn init_node_list(&mut self, mut nodes: Vec) { + pub fn init_node_list(&mut self, mut nodes: Vec) { for n in nodes.drain(..) { self.update_node(n); } @@ -243,7 +243,7 @@ impl Discovery { self.send_to(packet, address.clone()); } - #[cfg_attr(feature="dev", allow(map_clone))] + #[cfg_attr(all(nightly, feature="dev"), allow(map_clone))] fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { let mut found: BTreeMap> = BTreeMap::new(); let mut count = 0; @@ -251,7 +251,7 @@ impl Discovery { // Sort nodes by distance to target for bucket in buckets { for node in &bucket.nodes { - let distance = Discovery::distance(target, &node.address.id); + let distance = Discovery::distance(target, &node.address.id); found.entry(distance).or_insert_with(Vec::new).push(&node.address); if count == BUCKET_SIZE { // delete the most distant element @@ -310,7 +310,7 @@ impl Discovery { None }), Ok(_) => None, - Err(e) => { + Err(e) => { warn!("Error reading UPD socket: {:?}", e); None } @@ -339,7 +339,7 @@ impl Discovery { PACKET_PONG => self.on_pong(&rlp, &node_id, &from), PACKET_FIND_NODE => self.on_find_node(&rlp, &node_id, &from), PACKET_NEIGHBOURS => self.on_neighbours(&rlp, &node_id, &from), - _ => { + _ => { debug!("Unknown UDP packet: {}", packet_id); Ok(None) } @@ -367,14 +367,14 @@ impl Discovery { } else { self.update_node(entry.clone()); - added_map.insert(node.clone(), entry); + added_map.insert(node.clone(), entry); } let hash = rlp.as_raw().sha3(); let mut response = RlpStream::new_list(2); dest.to_rlp_list(&mut response); response.append(&hash); self.send_packet(PACKET_PONG, from, &response.drain()); - + Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) } @@ -391,7 +391,7 @@ impl Discovery { } self.clear_ping(node); let mut added_map = HashMap::new(); - added_map.insert(node.clone(), entry); + added_map.insert(node.clone(), entry); Ok(None) } @@ -466,8 +466,8 @@ impl Discovery { pub fn round(&mut self) -> Option { let removed = self.check_expired(false); self.discover(); - if !removed.is_empty() { - Some(TableUpdates { added: HashMap::new(), removed: removed }) + if !removed.is_empty() { + Some(TableUpdates { added: HashMap::new(), removed: removed }) } else { None } } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index ece24a1d1..2d1af55ba 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -507,7 +507,7 @@ impl Host where Message: Send + Sync + Clone { debug!(target: "network", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); } - #[cfg_attr(feature="dev", allow(single_match))] + #[cfg_attr(all(nightly, feature="dev"), allow(single_match))] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { @@ -542,7 +542,7 @@ impl Host where Message: Send + Sync + Clone { self.create_connection(socket, Some(id), io); } - #[cfg_attr(feature="dev", allow(block_in_if_condition_stmt))] + #[cfg_attr(all(nightly, feature="dev"), allow(block_in_if_condition_stmt))] fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) { let nonce = self.info.write().unwrap().next_nonce(); let mut handshakes = self.handshakes.write().unwrap(); diff --git a/util/src/panics.rs b/util/src/panics.rs index 05d266b8b..70ce0bc33 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -71,7 +71,7 @@ impl PanicHandler { /// Invoke closure and catch any possible panics. /// In case of panic notifies all listeners about it. - #[cfg_attr(feature="dev", allow(deprecated))] + #[cfg_attr(all(nightly, feature="dev"), allow(deprecated))] pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { let _guard = PanicGuard { handler: self }; let result = g(); diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index c4b5e120c..182b87063 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -22,7 +22,7 @@ use super::trietraits::*; use super::node::*; /// A `Trie` implementation using a generic `HashDB` backing database. -/// +/// /// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys` /// to get the keys belonging to the trie in the backing database, and `db_items_remaining()` to get /// which items in the backing database do not belong to this trie. If this is the only trie in the @@ -54,7 +54,7 @@ pub struct TrieDB<'db> { pub hash_count: usize, } -#[cfg_attr(feature="dev", allow(wrong_self_convention))] +#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] impl<'db> TrieDB<'db> { /// Create a new trie with the backing database `db` and `root` /// Panics, if `root` does not exist @@ -63,16 +63,16 @@ impl<'db> TrieDB<'db> { flushln!("TrieDB::new({}): Trie root not found!", root); panic!("Trie root not found!"); } - TrieDB { - db: db, + TrieDB { + db: db, root: root, - hash_count: 0 + hash_count: 0 } } /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { - self.db + pub fn db(&'db self) -> &'db HashDB { + self.db } /// Determine all the keys in the backing database that belong to the trie. @@ -142,7 +142,7 @@ impl<'db> TrieDB<'db> { /// Indentation helper for `formal_all`. fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result { - for _ in 0..size { + for _ in 0..size { try!(write!(f, " ")); } Ok(()) @@ -358,7 +358,7 @@ impl<'db> fmt::Debug for TrieDB<'db> { fn iterator() { use memorydb::*; use super::triedbmut::*; - + let d = vec![ &b"A"[..], &b"AA"[..], &b"AB"[..], &b"B"[..] ]; let mut memdb = MemoryDB::new(); diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 829c1e518..3d5c366e5 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -23,7 +23,7 @@ use super::journal::*; use super::trietraits::*; /// A `Trie` implementation using a generic `HashDB` backing database. -/// +/// /// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys` /// to get the keys belonging to the trie in the backing database, and `db_items_remaining()` to get /// which items in the backing database do not belong to this trie. If this is the only trie in the @@ -66,21 +66,21 @@ enum MaybeChanged<'a> { Changed(Bytes), } -#[cfg_attr(feature="dev", allow(wrong_self_convention))] +#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] impl<'db> TrieDBMut<'db> { /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. - pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { + pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { let mut r = TrieDBMut{ - db: db, + db: db, root: root, - hash_count: 0 - }; + hash_count: 0 + }; // set root rlp - *r.root = SHA3_NULL_RLP.clone(); - r + *r.root = SHA3_NULL_RLP.clone(); + r } /// Create a new trie with the backing database `db` and `root`. @@ -91,21 +91,21 @@ impl<'db> TrieDBMut<'db> { flushln!("Trie root not found {}", root); panic!("Trie root not found!"); } - TrieDBMut { - db: db, + TrieDBMut { + db: db, root: root, - hash_count: 0 + hash_count: 0 } } /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { - self.db + pub fn db(&'db self) -> &'db HashDB { + self.db } /// Get the backing database. - pub fn db_mut(&'db mut self) -> &'db mut HashDB { - self.db + pub fn db_mut(&'db mut self) -> &'db mut HashDB { + self.db } /// Determine all the keys in the backing database that belong to the trie. @@ -184,7 +184,7 @@ impl<'db> TrieDBMut<'db> { /// Indentation helper for `formal_all`. fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result { - for _ in 0..size { + for _ in 0..size { try!(write!(f, " ")); } Ok(()) @@ -350,7 +350,7 @@ impl<'db> TrieDBMut<'db> { } } - #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] /// Determine the RLP of the node, assuming we're inserting `partial` into the /// node currently of data `old`. This will *not* delete any hash of `old` from the database; /// it will just return the new RLP that includes the new node. @@ -378,7 +378,7 @@ impl<'db> TrieDBMut<'db> { // original had empty slot - place a leaf there. true if old_rlp.at(i).is_empty() => journal.new_node(Self::compose_leaf(&partial.mid(1), value), &mut s), // original has something there already; augment. - true => { + true => { let new = self.augmented(self.take_node(&old_rlp.at(i), journal), &partial.mid(1), value, journal); journal.new_node(new, &mut s); } From b61c0397bc476ca2253f43724646fc703eb0fdb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 14:36:38 +0100 Subject: [PATCH 416/753] removing unused variable --- util/src/journaldb.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 378bc2de5..35ad83fa0 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -617,7 +617,6 @@ mod tests { fn reopen_remove() { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let bar = H256::random(); let foo = { let mut jdb = JournalDB::new(dir.to_str().unwrap()); From ab42ec8c81bc91f82b3b81d404e5da2e81382aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 14:40:39 +0100 Subject: [PATCH 417/753] Removing unneeded lifetime --- ethcore/src/blockchain/generator/generator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/generator/generator.rs b/ethcore/src/blockchain/generator/generator.rs index 51e6294fc..88c9577e2 100644 --- a/ethcore/src/blockchain/generator/generator.rs +++ b/ethcore/src/blockchain/generator/generator.rs @@ -29,7 +29,7 @@ pub trait ChainIterator: Iterator + Sized { /// Blocks generated by fork will have lower difficulty than current chain. fn fork(&self, fork_number: usize) -> Fork where Self: Clone; /// Should be called to make every consecutive block have given bloom. - fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self>; + fn with_bloom(&mut self, bloom: H2048) -> Bloom; /// Should be called to complete block. Without complete, block may have incorrect hash. fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>; /// Completes and generates block. @@ -44,7 +44,7 @@ impl ChainIterator for I where I: Iterator + Sized { } } - fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self> { + fn with_bloom(&mut self, bloom: H2048) -> Bloom { Bloom { iter: self, bloom: bloom From 0fd52176dce0f9801ce0cd9c23ce38e187e23fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 16:26:35 +0100 Subject: [PATCH 418/753] Fixing tests in bigint and util --- test.sh | 9 ++++++- util/bigint/src/uint.rs | 52 -------------------------------------- util/src/lib.rs | 56 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 53 deletions(-) diff --git a/test.sh b/test.sh index 0f5edb0d1..dd71d120a 100755 --- a/test.sh +++ b/test.sh @@ -1,4 +1,11 @@ #!/bin/sh # Running Parity Full Test Sute -cargo test --features ethcore/json-tests $1 -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity +cargo test --features ethcore/json-tests $1 \ + -p ethash \ + -p ethcore-util \ + -p ethcore \ + -p ethsync \ + -p ethcore-rpc \ + -p parity \ + -p bigint diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index bd57e9d6d..62fcd8c6e 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -1948,58 +1948,6 @@ mod tests { assert_eq!(U256([1, 0, 0, 0]), result); } - #[test] - fn u256_multi_muls() { - use hash::*; - - let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); - assert_eq!(U256([0, 0, 0, 0]), result); - - let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); - assert_eq!(U256([1, 0, 0, 0]), result); - - let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); - assert_eq!(U256([25, 0, 0, 0]), result); - - let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); - assert_eq!(U256([0, 0, 25, 0]), result); - - let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); - assert_eq!(U256([0, 0, 0, 1]), result); - - let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); - assert_eq!(U256([0, 0, 0, 10]), result); - - let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); - assert_eq!(U256([0, 0, 0, 5]), result); - - let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); - assert_eq!(U256([0, 0, 0, 0]), result); - - let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); - assert_eq!(U256([0, 10, 0, 0]), result); - - let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); - assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); - - let x1 = U256::from_str("0000000000000000000000000000000000000000000000000000012365124623").unwrap(); - let x2sqr_right = U256::from_str("000000000000000000000000000000000000000000014baeef72e0378e2328c9").unwrap(); - let x1sqr = x1 * x1; - assert_eq!(H256::from(x2sqr_right), H256::from(x1sqr)); - let x1cube = x1sqr * x1; - let x1cube_right = U256::from_str("0000000000000000000000000000000001798acde139361466f712813717897b").unwrap(); - assert_eq!(H256::from(x1cube_right), H256::from(x1cube)); - let x1quad = x1cube * x1; - let x1quad_right = U256::from_str("000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1").unwrap(); - assert_eq!(H256::from(x1quad_right), H256::from(x1quad)); - let x1penta = x1quad * x1; - let x1penta_right = U256::from_str("00000000000001e92875ac24be246e1c57e0507e8c46cc8d233b77f6f4c72993").unwrap(); - assert_eq!(H256::from(x1penta_right), H256::from(x1penta)); - let x1septima = x1penta * x1; - let x1septima_right = U256::from_str("00022cca1da3f6e5722b7d3cc5bbfb486465ebc5a708dd293042f932d7eee119").unwrap(); - assert_eq!(H256::from(x1septima_right), H256::from(x1septima)); - } - #[test] fn u256_multi_muls_overflow() { let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); diff --git a/util/src/lib.rs b/util/src/lib.rs index a50ba8da4..344da0980 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -167,3 +167,59 @@ pub use io::*; pub use log::*; pub use kvdb::*; +#[cfg(test)] +mod tests { + use super::numbers::*; + use std::str::FromStr; + + #[test] + fn u256_multi_muls() { + + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([1, 0, 0, 0]), result); + + let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); + assert_eq!(U256([25, 0, 0, 0]), result); + + let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 25, 0]), result); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 1]), result); + + let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 10]), result); + + let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 0, 5]), result); + + let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 10, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + + let x1 = U256::from_str("0000000000000000000000000000000000000000000000000000012365124623").unwrap(); + let x2sqr_right = U256::from_str("000000000000000000000000000000000000000000014baeef72e0378e2328c9").unwrap(); + let x1sqr = x1 * x1; + assert_eq!(H256::from(x2sqr_right), H256::from(x1sqr)); + let x1cube = x1sqr * x1; + let x1cube_right = U256::from_str("0000000000000000000000000000000001798acde139361466f712813717897b").unwrap(); + assert_eq!(H256::from(x1cube_right), H256::from(x1cube)); + let x1quad = x1cube * x1; + let x1quad_right = U256::from_str("000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1").unwrap(); + assert_eq!(H256::from(x1quad_right), H256::from(x1quad)); + let x1penta = x1quad * x1; + let x1penta_right = U256::from_str("00000000000001e92875ac24be246e1c57e0507e8c46cc8d233b77f6f4c72993").unwrap(); + assert_eq!(H256::from(x1penta_right), H256::from(x1penta)); + let x1septima = x1penta * x1; + let x1septima_right = U256::from_str("00022cca1da3f6e5722b7d3cc5bbfb486465ebc5a708dd293042f932d7eee119").unwrap(); + assert_eq!(H256::from(x1septima_right), H256::from(x1septima)); + } +} From 4717be07d647c9a3fa1e0da5ec636a3d67a94d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 16:17:14 +0100 Subject: [PATCH 419/753] Optimizing mul_u32 --- util/benches/bigint.rs | 2 +- util/bigint/src/uint.rs | 49 ++++++++++++----------------------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 575164cb6..80c4ce1d8 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -79,7 +79,7 @@ fn u256_full_mul(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), - |old, new| { + |old, _new| { let U512(ref u512words) = old.full_mul(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()])); U256([u512words[0], u512words[2], u512words[2], u512words[3]]) }) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 62fcd8c6e..ad4f0a99c 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -711,52 +711,31 @@ macro_rules! construct_uint { #[allow(dead_code)] // not used when multiplied with inline assembly /// Multiplication by u32 fn mul_u32(self, other: u32) -> Self { - let $name(ref arr) = self; - let mut carry = [0u64; $n_words]; - let mut ret = [0u64; $n_words]; - for i in 0..$n_words { - let upper = other as u64 * (arr[i] >> 32); - let lower = other as u64 * (arr[i] & 0xFFFFFFFF); - - ret[i] = lower.wrapping_add(upper << 32); - - if i < $n_words - 1 { - carry[i + 1] = upper >> 32; - if ret[i] < lower { - carry[i + 1] += 1; - } - } - } - $name(ret) + $name(carry) + let (ret, overflow) = self.overflowing_mul_u32(other); + panic_on_overflow!(overflow); + ret } #[allow(dead_code)] // not used when multiplied with inline assembly /// Overflowing multiplication by u32 fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { let $name(ref arr) = self; - let mut carry = [0u64; $n_words]; + let o = other as u64; + let mut carry = [0u64; $n_words + 1]; let mut ret = [0u64; $n_words]; - let mut overflow = false; + for i in 0..$n_words { - let upper = other as u64 * (arr[i] >> 32); - let lower = other as u64 * (arr[i] & 0xFFFFFFFF); + let upper = o * (arr[i] >> 32); + let lower = o * (arr[i] & 0xFFFFFFFF); - ret[i] = lower.wrapping_add(upper << 32); + let (res1, overflow1) = lower.overflowing_add(upper << 32); + let (res2, overflow2) = res1.overflowing_add(carry[i]); - if i < $n_words - 1 { - carry[i + 1] = upper >> 32; - if ret[i] < lower { - carry[i + 1] += 1; - } - } else if (upper >> 32) > 0 || ret[i] < lower { - overflow = true - } + ret[i] = res2; + carry[i + 1] = (upper >> 32) + overflow1 as u64 + overflow2 as u64; } - let result = overflowing!( - $name(ret).overflowing_add($name(carry)), - overflow - ); - (result, overflow) + + ($name(ret), carry[$n_words] > 0) } } From cc0adf544208a36786e0ffa7f219ff79983d380b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 17:06:08 +0100 Subject: [PATCH 420/753] Optimizing and simplifying add and shl --- util/bigint/src/uint.rs | 89 ++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 55 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index ad4f0a99c..47a975d5f 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -71,29 +71,19 @@ macro_rules! uint_overflowing_add_reg { ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ let $name(ref me) = $self_expr; let $name(ref you) = $other; + let mut ret = [0u64; $n_words]; - let mut carry = [0u64; $n_words]; - let mut b_carry = false; - let mut overflow = false; + let mut carry = [0u64; $n_words + 1]; for i in 0..$n_words { - ret[i] = me[i].wrapping_add(you[i]); + let (res1, overflow1) = me[i].overflowing_add(you[i]); + let (res2, overflow2) = res1.overflowing_add(carry[i]); - if ret[i] < me[i] { - if i < $n_words - 1 { - carry[i + 1] = 1; - b_carry = true; - } else { - overflow = true; - } - } - } - if b_carry { - let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow); - (ret, overflow) - } else { - ($name(ret), overflow) + ret[i] = res2; + carry[i+1] = overflow1 as u64 + overflow2 as u64; } + + ($name(ret), carry[$n_words] > 0) }) } @@ -673,37 +663,10 @@ macro_rules! construct_uint { } fn overflowing_shl(self, shift32: u32) -> ($name, bool) { - let $name(ref original) = self; - let mut ret = [0u64; $n_words]; let shift = shift32 as usize; - let word_shift = shift / 64; - let bit_shift = shift % 64; - for i in 0..$n_words { - // Shift - if i + word_shift < $n_words { - ret[i + word_shift] += original[i] << bit_shift; - } - // Carry - if bit_shift > 0 && i + word_shift + 1 < $n_words { - ret[i + word_shift + 1] += original[i] >> (64 - bit_shift); - } - } - // Detecting overflow - let last = $n_words - word_shift - if bit_shift > 0 { 1 } else { 0 }; - let overflow = if bit_shift > 0 { - (original[last] >> (64 - bit_shift)) > 0 - } else if word_shift > 0 { - original[last] > 0 - } else { - false - }; - for i in last+1..$n_words-1 { - if original[i] > 0 { - return ($name(ret), true); - } - } - ($name(ret), overflow) + let res = self << shift; + (res, self != (res >> shift)) } } @@ -987,14 +950,15 @@ macro_rules! construct_uint { let mut ret = [0u64; $n_words]; let word_shift = shift / 64; let bit_shift = shift % 64; - for i in 0..$n_words { - // Shift - if i + word_shift < $n_words { - ret[i + word_shift] += original[i] << bit_shift; - } - // Carry - if bit_shift > 0 && i + word_shift + 1 < $n_words { - ret[i + word_shift + 1] += original[i] >> (64 - bit_shift); + + // shift + for i in word_shift..$n_words { + ret[i] += original[i - word_shift] << bit_shift; + } + // carry + if bit_shift > 0 { + for i in word_shift+1..$n_words { + ret[i] += original[i - 1 - word_shift] >> (64 - bit_shift); } } $name(ret) @@ -1672,6 +1636,11 @@ mod tests { #[test] pub fn uint256_shl_overflow() { + assert_eq!( + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 4, + U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap() + ); assert_eq!( U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() .overflowing_shl(4), @@ -1681,6 +1650,16 @@ mod tests { #[test] pub fn uint256_shl_overflow_words() { + assert_eq!( + U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 64, + U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap() + ); + assert_eq!( + U256::from_str("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 64, + U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap() + ); assert_eq!( U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() .overflowing_shl(64), From e7be3c5378c50f2a11d053003946d958a93edf1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 17:09:19 +0100 Subject: [PATCH 421/753] Simplifing mul_u32 and add carry --- util/bigint/src/uint.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 47a975d5f..789fc744e 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -73,17 +73,17 @@ macro_rules! uint_overflowing_add_reg { let $name(ref you) = $other; let mut ret = [0u64; $n_words]; - let mut carry = [0u64; $n_words + 1]; + let mut carry = 0u64; for i in 0..$n_words { let (res1, overflow1) = me[i].overflowing_add(you[i]); - let (res2, overflow2) = res1.overflowing_add(carry[i]); + let (res2, overflow2) = res1.overflowing_add(carry); ret[i] = res2; - carry[i+1] = overflow1 as u64 + overflow2 as u64; + carry = overflow1 as u64 + overflow2 as u64; } - ($name(ret), carry[$n_words] > 0) + ($name(ret), carry > 0) }) } @@ -684,21 +684,21 @@ macro_rules! construct_uint { fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { let $name(ref arr) = self; let o = other as u64; - let mut carry = [0u64; $n_words + 1]; let mut ret = [0u64; $n_words]; + let mut carry = 0; for i in 0..$n_words { let upper = o * (arr[i] >> 32); let lower = o * (arr[i] & 0xFFFFFFFF); let (res1, overflow1) = lower.overflowing_add(upper << 32); - let (res2, overflow2) = res1.overflowing_add(carry[i]); + let (res2, overflow2) = res1.overflowing_add(carry); ret[i] = res2; - carry[i + 1] = (upper >> 32) + overflow1 as u64 + overflow2 as u64; + carry = (upper >> 32) + overflow1 as u64 + overflow2 as u64; } - ($name(ret), carry[$n_words] > 0) + ($name(ret), carry > 0) } } From c5840be1cb1a55d0daf1c208dbfd3c7bcdea6c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 18:36:17 +0100 Subject: [PATCH 422/753] Small improvements --- util/bigint/src/uint.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 789fc744e..8fbaca532 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -379,11 +379,24 @@ macro_rules! uint_overflowing_mul_reg { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let mut res = $name::from(0u64); let mut overflow = false; - for i in 0..(2 * $n_words) { - let v = overflowing!($self_expr.overflowing_mul_u32(($other >> (32 * i)).low_u32()), overflow); - let res2 = overflowing!(v.overflowing_shl(32 * i as u32), overflow); - res = overflowing!(res.overflowing_add(res2), overflow); + + let mut current = $other; + let mut current_shift = 0; + let mut current_u32; + let mut i = 0; + + while i < 2*$n_words { + current_u32 = current.low_u32(); + + let v = overflowing!($self_expr.overflowing_mul_u32(current_u32), overflow); + let v_shifted = overflowing!(v.overflowing_shl(current_shift), overflow); + res = overflowing!(res.overflowing_add(v_shifted), overflow); + + current = current >> 32; + current_shift += 32; + i += 1; } + (res, overflow) }) } @@ -973,6 +986,7 @@ macro_rules! construct_uint { let mut ret = [0u64; $n_words]; let word_shift = shift / 64; let bit_shift = shift % 64; + for i in word_shift..$n_words { // Shift ret[i - word_shift] += original[i] >> bit_shift; @@ -989,9 +1003,11 @@ macro_rules! construct_uint { fn cmp(&self, other: &$name) -> Ordering { let &$name(ref me) = self; let &$name(ref you) = other; - for i in 0..$n_words { - if me[$n_words - 1 - i] < you[$n_words - 1 - i] { return Ordering::Less; } - if me[$n_words - 1 - i] > you[$n_words - 1 - i] { return Ordering::Greater; } + let mut i = $n_words; + while i > 0 { + i -= 1; + if me[i] < you[i] { return Ordering::Less; } + if me[i] > you[i] { return Ordering::Greater; } } Ordering::Equal } From 76865694ce705b945655b685e05ef21ade44e8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 7 Mar 2016 19:03:29 +0100 Subject: [PATCH 423/753] Subtraction optimization --- util/bigint/src/uint.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 8fbaca532..0e8d1e7b7 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -166,9 +166,22 @@ macro_rules! uint_overflowing_add { #[cfg(not(all(asm_available, target_arch="x86_64")))] macro_rules! uint_overflowing_sub { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ - let res = overflowing!((!$other).overflowing_add(From::from(1u64))); - let res = overflowing!($self_expr.overflowing_add(res)); - (res, $self_expr < $other) + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + + let mut ret = [0u64; $n_words]; + let mut carry = 0u64; + + for i in 0..$n_words { + let (res1, overflow1) = me[i].overflowing_sub(you[i]); + let (res2, overflow2) = res1.overflowing_sub(carry); + + ret[i] = res2; + carry = overflow1 as u64 + overflow2 as u64; + } + + ($name(ret), carry > 0) + }) } From 17b2d2a2d71897d55bf869d7da194bc730a71a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 01:13:00 +0100 Subject: [PATCH 424/753] Implementing mul and full_mul --- util/bigint/src/uint.rs | 180 +++++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 84 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 0e8d1e7b7..6a6658235 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -390,27 +390,47 @@ macro_rules! uint_overflowing_mul { macro_rules! uint_overflowing_mul_reg { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ - let mut res = $name::from(0u64); - let mut overflow = false; + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + let mut ret = [0u64; 2*$n_words]; - let mut current = $other; - let mut current_shift = 0; - let mut current_u32; - let mut i = 0; + for i in 0..$n_words { + let mut carry2 = 0u64; + let (b_u, b_l) = (you[i] >> 32, you[i] & 0xFFFFFFFF); - while i < 2*$n_words { - current_u32 = current.low_u32(); + for j in 0..$n_words { + let a = me[j]; - let v = overflowing!($self_expr.overflowing_mul_u32(current_u32), overflow); - let v_shifted = overflowing!(v.overflowing_shl(current_shift), overflow); - res = overflowing!(res.overflowing_add(v_shifted), overflow); + // multiply parts + let (c_l, overflow_l) = mul_u32(a, b_l as u32, ret[j + i]); + let (c_u, overflow_u) = mul_u32(a, b_u as u32, c_l >> 32); - current = current >> 32; - current_shift += 32; - i += 1; + // This won't overflow + ret[j + i] = (c_l & 0xFFFFFFFF) + (c_u << 32); + + // carry1 = overflow_l + (c_u >> 32) + (overflow_u << 32) + carry2 + c0; + let (ca1, c1) = overflow_l.overflowing_add((c_u >> 32) + (overflow_u << 32)); + let (ca1, c2) = ca1.overflowing_add(ret[j + i + 1]); + let (ca1, c3) = ca1.overflowing_add(carry2); + + ret[j + i + 1] = ca1; + + // Will never overflow + carry2 = (overflow_u >> 32) + c1 as u64 + c2 as u64 + c3 as u64; + } } - (res, overflow) + let mut res = [0u64; $n_words]; + let mut overflow = false; + for i in 0..$n_words { + res[i] = ret[i]; + } + + for i in $n_words..2*$n_words { + overflow |= ret[i] != 0; + } + + ($name(res), overflow) }) } @@ -438,6 +458,19 @@ macro_rules! panic_on_overflow { } } +#[inline(always)] +fn mul_u32(a: u64, b: u32, carry: u64) -> (u64, u64) { + let b = b as u64; + let upper = b * (a >> 32); + let lower = b * (a & 0xFFFFFFFF); + + let (res1, overflow1) = lower.overflowing_add(upper << 32); + let (res2, overflow2) = res1.overflowing_add(carry); + + let carry = (upper >> 32) + overflow1 as u64 + overflow2 as u64; + (res2, carry) +} + /// Large, fixed-length unsigned integer type. pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { @@ -496,9 +529,6 @@ pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Displa /// Returns negation of this `Uint` and overflow (always true) fn overflowing_neg(self) -> (Self, bool); - - /// Shifts this `Uint` and returns overflow - fn overflowing_shl(self, shift: u32) -> (Self, bool); } macro_rules! construct_uint { @@ -687,13 +717,6 @@ macro_rules! construct_uint { fn overflowing_neg(self) -> ($name, bool) { (!self, true) } - - fn overflowing_shl(self, shift32: u32) -> ($name, bool) { - let shift = shift32 as usize; - - let res = self << shift; - (res, self != (res >> shift)) - } } impl $name { @@ -709,19 +732,13 @@ macro_rules! construct_uint { /// Overflowing multiplication by u32 fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { let $name(ref arr) = self; - let o = other as u64; let mut ret = [0u64; $n_words]; let mut carry = 0; for i in 0..$n_words { - let upper = o * (arr[i] >> 32); - let lower = o * (arr[i] & 0xFFFFFFFF); - - let (res1, overflow1) = lower.overflowing_add(upper << 32); - let (res2, overflow2) = res1.overflowing_add(carry); - - ret[i] = res2; - carry = (upper >> 32) + overflow1 as u64 + overflow2 as u64; + let (res, carry2) = mul_u32(arr[i], other, carry); + ret[i] = res; + carry = carry2; } ($name(ret), carry > 0) @@ -1233,10 +1250,37 @@ impl U256 { /// No overflow possible #[cfg(not(all(asm_available, target_arch="x86_64")))] pub fn full_mul(self, other: U256) -> U512 { - let self_512 = U512::from(self); - let other_512 = U512::from(other); - let (result, _) = self_512.overflowing_mul(other_512); - result + let U256(ref me) = self; + let U256(ref you) = other; + let mut ret = [0u64; 8]; + + for i in 0..4 { + let mut carry2 = 0u64; + let (b_u, b_l) = (you[i] >> 32, you[i] & 0xFFFFFFFF); + + for j in 0..4 { + let a = me[j]; + + // multiply parts + let (c_l, overflow_l) = mul_u32(a, b_l as u32, ret[j + i]); + let (c_u, overflow_u) = mul_u32(a, b_u as u32, c_l >> 32); + + // This won't overflow + ret[j + i] = (c_l & 0xFFFFFFFF) + (c_u << 32); + + // carry1 = overflow_l + (c_u >> 32) + (overflow_u << 32) + carry2 + c0; + let (ca1, c1) = overflow_l.overflowing_add((c_u >> 32) + (overflow_u << 32)); + let (ca1, c2) = ca1.overflowing_add(ret[j + i + 1]); + let (ca1, c3) = ca1.overflowing_add(carry2); + + ret[j + i + 1] = ca1; + + // Will never overflow + carry2 = (overflow_u >> 32) + c1 as u64 + c2 as u64 + c3 as u64; + } + } + + U512(ret) } } @@ -1502,6 +1546,18 @@ mod tests { //// TODO: bit inversion } + #[test] + pub fn uint256_simple_mul() { + let a = U256::from_str("10000000000000000").unwrap(); + let b = U256::from_str("10000000000000000").unwrap(); + + let c = U256::from_str("100000000000000000000000000000000").unwrap(); + println!("Multiplying"); + let result = a.overflowing_mul(b); + println!("Got result"); + assert_eq!(result, (c, false)) + } + #[test] pub fn uint256_extreme_bitshift_test() { //// Shifting a u64 by 64 bits gives an undefined value, so make sure that @@ -1664,21 +1720,16 @@ mod tests { } #[test] - pub fn uint256_shl_overflow() { + pub fn uint256_shl() { assert_eq!( U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() << 4, U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap() ); - assert_eq!( - U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(4), - (U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap(), true) - ); } #[test] - pub fn uint256_shl_overflow_words() { + pub fn uint256_shl_words() { assert_eq!( U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() << 64, @@ -1689,45 +1740,6 @@ mod tests { << 64, U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap() ); - assert_eq!( - U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(64), - (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap(), true) - ); - assert_eq!( - U256::from_str("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(64), - (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap(), false) - ); - } - - #[test] - pub fn uint256_shl_overflow_words2() { - assert_eq!( - U256::from_str("00000000000000000000000000000001ffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(128), - (U256::from_str("ffffffffffffffffffffffffffffffff00000000000000000000000000000000").unwrap(), true) - ); - assert_eq!( - U256::from_str("00000000000000000000000000000000ffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(128), - (U256::from_str("ffffffffffffffffffffffffffffffff00000000000000000000000000000000").unwrap(), false) - ); - assert_eq!( - U256::from_str("00000000000000000000000000000000ffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(129), - (U256::from_str("fffffffffffffffffffffffffffffffe00000000000000000000000000000000").unwrap(), true) - ); - } - - - #[test] - pub fn uint256_shl_overflow2() { - assert_eq!( - U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(4), - (U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap(), false) - ); } #[test] From 9ae2341ba9ba33af6e0baa4e0a9ee335c90bf56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 10:05:46 +0100 Subject: [PATCH 425/753] Couple of more aggresive optimizations --- util/bigint/src/uint.rs | 81 +++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 6a6658235..68af6dad8 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -395,28 +395,31 @@ macro_rules! uint_overflowing_mul_reg { let mut ret = [0u64; 2*$n_words]; for i in 0..$n_words { + if you[i] == 0 { + continue; + } + let mut carry2 = 0u64; - let (b_u, b_l) = (you[i] >> 32, you[i] & 0xFFFFFFFF); + let (b_u, b_l) = split(you[i]); for j in 0..$n_words { - let a = me[j]; + if me[j] == 0 { + continue; + } + + let a = split(me[j]); // multiply parts - let (c_l, overflow_l) = mul_u32(a, b_l as u32, ret[j + i]); - let (c_u, overflow_u) = mul_u32(a, b_u as u32, c_l >> 32); + let (c_l, overflow_l) = mul_u32(a, b_l, ret[i + j]); + let (c_u, overflow_u) = mul_u32(a, b_u, c_l >> 32); + ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32); - // This won't overflow - ret[j + i] = (c_l & 0xFFFFFFFF) + (c_u << 32); + // Only single overflow possible here + let carry = (c_u >> 32) + (overflow_u << 32) + overflow_l + carry2; + let (carry, o) = carry.overflowing_add(ret[i + j + 1]); - // carry1 = overflow_l + (c_u >> 32) + (overflow_u << 32) + carry2 + c0; - let (ca1, c1) = overflow_l.overflowing_add((c_u >> 32) + (overflow_u << 32)); - let (ca1, c2) = ca1.overflowing_add(ret[j + i + 1]); - let (ca1, c3) = ca1.overflowing_add(carry2); - - ret[j + i + 1] = ca1; - - // Will never overflow - carry2 = (overflow_u >> 32) + c1 as u64 + c2 as u64 + c3 as u64; + ret[i + j + 1] = carry; + carry2 = o as u64; } } @@ -459,10 +462,9 @@ macro_rules! panic_on_overflow { } #[inline(always)] -fn mul_u32(a: u64, b: u32, carry: u64) -> (u64, u64) { - let b = b as u64; - let upper = b * (a >> 32); - let lower = b * (a & 0xFFFFFFFF); +fn mul_u32(a: (u64, u64), b: u64, carry: u64) -> (u64, u64) { + let upper = b * a.0; + let lower = b * a.1; let (res1, overflow1) = lower.overflowing_add(upper << 32); let (res2, overflow2) = res1.overflowing_add(carry); @@ -471,6 +473,11 @@ fn mul_u32(a: u64, b: u32, carry: u64) -> (u64, u64) { (res2, carry) } +#[inline(always)] +fn split(a: u64) -> (u64, u64) { + (a >> 32, a & 0xFFFFFFFF) +} + /// Large, fixed-length unsigned integer type. pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { @@ -734,9 +741,10 @@ macro_rules! construct_uint { let $name(ref arr) = self; let mut ret = [0u64; $n_words]; let mut carry = 0; + let o = other as u64; for i in 0..$n_words { - let (res, carry2) = mul_u32(arr[i], other, carry); + let (res, carry2) = mul_u32(split(arr[i]), o, carry); ret[i] = res; carry = carry2; } @@ -1255,28 +1263,31 @@ impl U256 { let mut ret = [0u64; 8]; for i in 0..4 { + if you[i] == 0 { + continue; + } + let mut carry2 = 0u64; - let (b_u, b_l) = (you[i] >> 32, you[i] & 0xFFFFFFFF); + let (b_u, b_l) = split(you[i]); for j in 0..4 { - let a = me[j]; + if me[j] == 0 { + continue; + } + + let a = split(me[j]); // multiply parts - let (c_l, overflow_l) = mul_u32(a, b_l as u32, ret[j + i]); - let (c_u, overflow_u) = mul_u32(a, b_u as u32, c_l >> 32); + let (c_l, overflow_l) = mul_u32(a, b_l, ret[i + j]); + let (c_u, overflow_u) = mul_u32(a, b_u, c_l >> 32); + ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32); - // This won't overflow - ret[j + i] = (c_l & 0xFFFFFFFF) + (c_u << 32); + // Only single overflow possible here + let carry = (c_u >> 32) + (overflow_u << 32) + overflow_l + carry2; + let (carry, o) = carry.overflowing_add(ret[i + j + 1]); - // carry1 = overflow_l + (c_u >> 32) + (overflow_u << 32) + carry2 + c0; - let (ca1, c1) = overflow_l.overflowing_add((c_u >> 32) + (overflow_u << 32)); - let (ca1, c2) = ca1.overflowing_add(ret[j + i + 1]); - let (ca1, c3) = ca1.overflowing_add(carry2); - - ret[j + i + 1] = ca1; - - // Will never overflow - carry2 = (overflow_u >> 32) + c1 as u64 + c2 as u64 + c3 as u64; + ret[i + j + 1] = carry; + carry2 = o as u64; } } From c47209e9bf25b72684aa4699c6a70a1dfe6307b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 12:09:04 +0100 Subject: [PATCH 426/753] Using better subtraction when optimizations are enabled --- util/bigint/src/uint.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 68af6dad8..801c5f5bd 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -165,6 +165,12 @@ macro_rules! uint_overflowing_add { #[cfg(not(all(asm_available, target_arch="x86_64")))] macro_rules! uint_overflowing_sub { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_sub_reg { ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ let $name(ref me) = $self_expr; let $name(ref you) = $other; @@ -255,9 +261,7 @@ macro_rules! uint_overflowing_sub { (U512(result), overflow != 0) }); ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ - let res = overflowing!((!$other).overflowing_add(From::from(1u64))); - let res = overflowing!($self_expr.overflowing_add(res)); - (res, $self_expr < $other) + uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other) }) } From 655bb0ed5db4eb014d959b03b3edc43cfb5ebf4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 12:36:06 +0100 Subject: [PATCH 427/753] Additional documentation for transaction queue --- sync/src/lib.rs | 1 + sync/src/transaction_queue.rs | 103 +++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/sync/src/lib.rs b/sync/src/lib.rs index b5869642c..39a06af8f 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -72,6 +72,7 @@ mod chain; mod io; mod range_collection; mod transaction_queue; +pub use transaction_queue::TransactionQueue; #[cfg(test)] mod tests; diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 3e0d931b5..8270c6e27 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -17,6 +17,67 @@ // TODO [todr] - own transactions should have higher priority //! Transaction Queue +//! +//! TransactionQueue keeps track of all transactions seen by the node (received from other peers) and own transactions +//! and orders them by priority. Top priority transactions are those with low nonce height (difference between +//! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used +//! for comparison (higher gas price = higher priority). +//! +//! # Usage Example +//! +//! ```rust +//! extern crate ethcore_util as util; +//! extern crate ethcore; +//! extern crate ethsync; +//! extern crate rustc_serialize; +//! +//! use util::crypto::KeyPair; +//! use util::hash::Address; +//! use util::numbers::{Uint, U256}; +//! use ethsync::TransactionQueue; +//! use ethcore::transaction::*; +//! use rustc_serialize::hex::FromHex; +//! +//! fn main() { +//! let key = KeyPair::create().unwrap(); +//! let t1 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), +//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(10) }; +//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), +//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) }; +//! +//! let st1 = t1.sign(&key.secret()); +//! let st2 = t2.sign(&key.secret()); +//! let default_nonce = |_a: &Address| U256::from(10); +//! +//! let mut txq = TransactionQueue::new(); +//! txq.add(st2.clone(), &default_nonce); +//! txq.add(st1.clone(), &default_nonce); +//! +//! // Check status +//! assert_eq!(txq.status().pending, 2); +//! // Check top transactions +//! let top = txq.top_transactions(3); +//! assert_eq!(top.len(), 2); +//! assert_eq!(top[0], st1); +//! assert_eq!(top[1], st2); +//! +//! // And when transaction is removed (but nonce haven't changed) +//! // it will move invalid transactions to future +//! txq.remove(&st1.hash(), &default_nonce); +//! assert_eq!(txq.status().pending, 0); +//! assert_eq!(txq.status().future, 1); +//! assert_eq!(txq.top_transactions(3).len(), 0); +//! } +//! +//! +//! # Maintaing valid state +//! +//! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling). +//! 2. Whenever transaction is removed: +//! - When it's removed from `future` - all `future` transactions heights are recalculated and then +//! we check if the transactions should go to `current` (comparing state nonce) +//! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated. +//! use std::cmp::{Ordering}; use std::collections::{HashMap, BTreeSet}; @@ -27,9 +88,16 @@ use ethcore::transaction::*; #[derive(Clone, Debug)] +/// Light structure used to identify transaction and it's order struct TransactionOrder { + /// Primary ordering factory. Difference between transaction nonce and expected nonce in state + /// (e.g. Tx(nonce:5), State(nonce:0) -> height: 5) + /// High nonce_height = Low priority (processed later) nonce_height: U256, + /// Gas Price of the transaction. + /// Low gas price = Low priority (processed later) gas_price: U256, + /// Hash to identify associated transaction hash: H256, } @@ -70,7 +138,7 @@ impl Ord for TransactionOrder { let a_gas = self.gas_price; let b_gas = b.gas_price; if a_gas != b_gas { - return a_gas.cmp(&b_gas); + return b_gas.cmp(&a_gas); } // Compare hashes @@ -78,6 +146,7 @@ impl Ord for TransactionOrder { } } +/// Verified transaction (with sender) struct VerifiedTransaction { transaction: SignedTransaction } @@ -101,6 +170,11 @@ impl VerifiedTransaction { } } +/// Holds transactions accessible by (address, nonce) and by priority +/// +/// TransactionSet keeps number of entries below limit, but it doesn't +/// automatically happen during `insert/remove` operations. +/// You have to call `enforce_limit` to remove lowest priority transactions from set. struct TransactionSet { by_priority: BTreeSet, by_address: Table, @@ -108,11 +182,15 @@ struct TransactionSet { } impl TransactionSet { + /// Inserts `TransactionOrder` to this set fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) -> Option { self.by_priority.insert(order.clone()); self.by_address.insert(sender, nonce, order) } + /// Remove low priority transactions if there is more then specified by given `limit`. + /// + /// It drops transactions from this set but also removes associated `VerifiedTransaction`. fn enforce_limit(&mut self, by_hash: &mut HashMap) { let len = self.by_priority.len(); if len <= self.limit { @@ -134,6 +212,7 @@ impl TransactionSet { } } + /// Drop transaction from this set (remove from `by_priority` and `by_address`) fn drop(&mut self, sender: &Address, nonce: &U256) -> Option { if let Some(tx_order) = self.by_address.remove(sender, nonce) { self.by_priority.remove(&tx_order); @@ -142,6 +221,7 @@ impl TransactionSet { None } + /// Drop all transactions. fn clear(&mut self) { self.by_priority.clear(); self.by_address.clear(); @@ -260,6 +340,8 @@ impl TransactionQueue { // We will either move transaction to future or remove it completely // so there will be no transactions from this sender in current self.last_nonces.remove(&sender); + // First update height of transactions in future to avoid collisions + self.update_future(&sender, current_nonce); // This should move all current transactions to future and remove old transactions self.move_all_to_future(&sender, current_nonce); // And now lets check if there is some chain of transactions in future @@ -269,6 +351,7 @@ impl TransactionQueue { } } + /// Update height of all transactions in future transactions set. fn update_future(&mut self, sender: &Address, current_nonce: U256) { // We need to drain all transactions for current sender from future and reinsert them with updated height let all_nonces_from_sender = match self.future.by_address.row(&sender) { @@ -281,6 +364,8 @@ impl TransactionQueue { } } + /// Drop all transactions from given sender from `current`. + /// Either moves them to `future` or removes them from queue completely. fn move_all_to_future(&mut self, sender: &Address, current_nonce: U256) { let all_nonces_from_sender = match self.current.by_address.row(&sender) { Some(row_map) => row_map.keys().cloned().collect::>(), @@ -300,7 +385,7 @@ impl TransactionQueue { } - /// Returns top transactions from the queue + /// Returns top transactions from the queue ordered by priority. pub fn top_transactions(&self, size: usize) -> Vec { self.current.by_priority .iter() @@ -318,6 +403,8 @@ impl TransactionQueue { self.last_nonces.clear(); } + /// Checks if there are any transactions in `future` that should actually be promoted to `current` + /// (because nonce matches). fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { { let by_nonce = self.future.by_address.row_mut(&address); @@ -339,6 +426,14 @@ impl TransactionQueue { self.last_nonces.insert(address, current_nonce - U256::one()); } + /// Adds VerifiedTransaction to this queue. + /// + /// Determines if it should be placed in current or future. When transaction is + /// imported to `current` also checks if there are any `future` transactions that should be promoted because of + /// this. + /// + /// It ignores transactions that has already been imported (same `hash`) and replaces the transaction + /// iff `(address, nonce)` is the same but `gas_price` is higher. fn import_tx(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) where T: Fn(&Address) -> U256 { @@ -377,6 +472,10 @@ impl TransactionQueue { self.current.enforce_limit(&mut self.by_hash); } + /// Replaces transaction in given set (could be `future` or `current`). + /// + /// If there is already transaction with same `(sender, nonce)` it will be replaced iff `gas_price` is higher. + /// One of the transactions is dropped from set and also removed from queue entirely (from `by_hash`). fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, set: &mut TransactionSet, by_hash: &mut HashMap) { let order = TransactionOrder::for_transaction(&tx, base_nonce); let hash = tx.hash(); From 799d3bd2c8e15e71a027caf7e8c836b578163161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 12:42:32 +0100 Subject: [PATCH 428/753] Fixing doc test for queue --- sync/src/transaction_queue.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 8270c6e27..4b4a6226b 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -68,7 +68,7 @@ //! assert_eq!(txq.status().future, 1); //! assert_eq!(txq.top_transactions(3).len(), 0); //! } -//! +//! ``` //! //! # Maintaing valid state //! From 99a6802b619cb3c1c821ed9645d509dfc9cbc9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 15:46:44 +0100 Subject: [PATCH 429/753] Moving block sealing and transaction_queue to separate create --- Cargo.lock | 18 ++- Cargo.toml | 1 + ethcore/src/client.rs | 105 ++++------------ miner/Cargo.toml | 20 +++ miner/src/lib.rs | 86 +++++++++++++ miner/src/miner.rs | 149 +++++++++++++++++++++++ {sync => miner}/src/transaction_queue.rs | 0 parity/main.rs | 73 ++++++----- rpc/Cargo.toml | 1 + rpc/src/lib.rs | 1 + rpc/src/v1/impls/eth.rs | 13 +- sync/Cargo.toml | 5 +- sync/src/chain.rs | 56 ++------- sync/src/lib.rs | 14 +-- 14 files changed, 375 insertions(+), 167 deletions(-) create mode 100644 miner/Cargo.toml create mode 100644 miner/src/lib.rs create mode 100644 miner/src/miner.rs rename {sync => miner}/src/transaction_queue.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 510e69b59..505fcac63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "ethcore-devtools 0.9.99", "ethcore-rpc 0.9.99", "ethcore-util 0.9.99", + "ethminer 0.9.99", "ethsync 0.9.99", "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -235,6 +236,7 @@ dependencies = [ "ethash 0.9.99", "ethcore 0.9.99", "ethcore-util 0.9.99", + "ethminer 0.9.99", "ethsync 0.9.99", "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -282,6 +284,19 @@ dependencies = [ "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethminer" +version = "0.9.99" +dependencies = [ + "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore 0.9.99", + "ethcore-util 0.9.99", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethsync" version = "0.9.99" @@ -290,11 +305,10 @@ dependencies = [ "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", + "ethminer 0.9.99", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 9b8ec6405..7e5bc334b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ clippy = { version = "0.0.44", optional = true } ethcore-util = { path = "util" } ethcore = { path = "ethcore" } ethsync = { path = "sync" } +ethminer = { path = "miner" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } daemonize = "0.2" diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 874fc9646..af1745ca8 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -17,7 +17,6 @@ //! Blockchain database client. use std::marker::PhantomData; -use std::sync::atomic::AtomicBool; use util::*; use util::panics::*; use blockchain::{BlockChain, BlockProvider}; @@ -185,6 +184,9 @@ pub trait BlockChainClient : Sync + Send { /// Returns logs matching given filter. fn logs(&self, filter: Filter) -> Vec; + + fn prepare_sealing(&self, author: Address, extra_data: Bytes) -> Option; + fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result; } #[derive(Default, Clone, Debug, Eq, PartialEq)] @@ -219,12 +221,6 @@ pub struct Client where V: Verifier { report: RwLock, import_lock: Mutex<()>, panic_handler: Arc, - - // for sealing... - sealing_enabled: AtomicBool, - sealing_block: Mutex>, - author: RwLock
, - extra_data: RwLock, verifier: PhantomData, secret_store: Arc>, } @@ -273,10 +269,6 @@ impl Client where V: Verifier { report: RwLock::new(Default::default()), import_lock: Mutex::new(()), panic_handler: panic_handler, - sealing_enabled: AtomicBool::new(false), - sealing_block: Mutex::new(None), - author: RwLock::new(Address::new()), - extra_data: RwLock::new(Vec::new()), verifier: PhantomData, secret_store: secret_store, })) @@ -425,10 +417,6 @@ impl Client where V: Verifier { } } - if self.chain_info().best_block_hash != original_best && self.sealing_enabled.load(atomic::Ordering::Relaxed) { - self.prepare_sealing(); - } - imported } @@ -477,85 +465,46 @@ impl Client where V: Verifier { BlockId::Latest => Some(self.chain.read().unwrap().best_block_number()) } } +} - /// Get the author that we will seal blocks as. - pub fn author(&self) -> Address { - self.author.read().unwrap().clone() + +// TODO: need MinerService MinerIoHandler + +impl BlockChainClient for Client where V: Verifier { + + + fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result { + block.try_seal(self.engine.deref().deref(), seal) } - /// Set the author that we will seal blocks as. - pub fn set_author(&self, author: Address) { - *self.author.write().unwrap() = author; - } - - /// Get the extra_data that we will seal blocks wuth. - pub fn extra_data(&self) -> Bytes { - self.extra_data.read().unwrap().clone() - } - - /// Set the extra_data that we will seal blocks with. - pub fn set_extra_data(&self, extra_data: Bytes) { - *self.extra_data.write().unwrap() = extra_data; - } - - /// New chain head event. Restart mining operation. - pub fn prepare_sealing(&self) { + fn prepare_sealing(&self, author: Address, extra_data: Bytes) -> Option { + let engine = self.engine.deref().deref(); let h = self.chain.read().unwrap().best_block_hash(); + let mut b = OpenBlock::new( - self.engine.deref().deref(), + engine, self.state_db.lock().unwrap().clone(), - match self.chain.read().unwrap().block_header(&h) { Some(ref x) => x, None => {return;} }, + match self.chain.read().unwrap().block_header(&h) { Some(ref x) => x, None => { return None; } }, self.build_last_hashes(h.clone()), - self.author(), - self.extra_data() + author, + extra_data, ); - self.chain.read().unwrap().find_uncle_headers(&h, self.engine.deref().deref().maximum_uncle_age()).unwrap().into_iter().take(self.engine.deref().deref().maximum_uncle_count()).foreach(|h| { b.push_uncle(h).unwrap(); }); + self.chain.read().unwrap().find_uncle_headers(&h, engine.maximum_uncle_age()) + .unwrap() + .into_iter() + .take(engine.maximum_uncle_count()) + .foreach(|h| { + b.push_uncle(h).unwrap(); + }); // TODO: push transactions. let b = b.close(); trace!("Sealing: number={}, hash={}, diff={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); - *self.sealing_block.lock().unwrap() = Some(b); + Some(b) } - /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - pub fn sealing_block(&self) -> &Mutex> { - if self.sealing_block.lock().unwrap().is_none() { - self.sealing_enabled.store(true, atomic::Ordering::Relaxed); - // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. - self.prepare_sealing(); - } - &self.sealing_block - } - - /// Submit `seal` as a valid solution for the header of `pow_hash`. - /// Will check the seal, but not actually insert the block into the chain. - pub fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { - let mut maybe_b = self.sealing_block.lock().unwrap(); - match *maybe_b { - Some(ref b) if b.hash() == pow_hash => {} - _ => { return Err(Error::PowHashInvalid); } - } - - let b = maybe_b.take(); - match b.unwrap().try_seal(self.engine.deref().deref(), seal) { - Err(old) => { - *maybe_b = Some(old); - Err(Error::PowInvalid) - } - Ok(sealed) => { - // TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice. - try!(self.import_block(sealed.rlp_bytes())); - Ok(()) - } - } - } -} - -// TODO: need MinerService MinerIoHandler - -impl BlockChainClient for Client where V: Verifier { fn block_header(&self, id: BlockId) -> Option { let chain = self.chain.read().unwrap(); Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) diff --git a/miner/Cargo.toml b/miner/Cargo.toml new file mode 100644 index 000000000..0972aa122 --- /dev/null +++ b/miner/Cargo.toml @@ -0,0 +1,20 @@ +[package] +description = "Ethminer library" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "ethminer" +version = "0.9.99" +authors = ["Ethcore "] + +[dependencies] +ethcore-util = { path = "../util" } +ethcore = { path = "../ethcore" } +log = "0.3" +env_logger = "0.3" +rustc-serialize = "0.3" +rayon = "0.3.1" +clippy = { version = "0.0.44", optional = true } + +[features] +dev = ["clippy"] +default = [] diff --git a/miner/src/lib.rs b/miner/src/lib.rs new file mode 100644 index 000000000..e8a50e9b5 --- /dev/null +++ b/miner/src/lib.rs @@ -0,0 +1,86 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#![warn(missing_docs)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] + +#[macro_use] +extern crate log; +#[macro_use] +extern crate ethcore_util as util; +extern crate ethcore; +extern crate env_logger; +extern crate rayon; + +mod miner; +mod transaction_queue; + +use util::{Bytes, H256, Address}; +use std::ops::*; +use std::sync::*; +use util::TimerToken; +use ethcore::block::*; +use ethcore::error::*; +use ethcore::client::{Client, BlockChainClient}; +use ethcore::transaction::*; +use miner::Miner; + +pub struct EthMiner { + miner: Miner, + /// Shared blockchain client. TODO: this should evetually become an IPC endpoint + chain: Arc, +} + +impl EthMiner { + /// Creates and register protocol with the network service + pub fn new(chain: Arc) -> Arc { + Arc::new(EthMiner { + miner: Miner::new(), + chain: chain, + }) + } + + pub fn sealing_block(&self) -> &Mutex> { + self.miner.sealing_block(self.chain.deref()) + } + + pub fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { + self.miner.submit_seal(self.chain.deref(), pow_hash, seal) + } + + /// Set the author that we will seal blocks as. + pub fn set_author(&self, author: Address) { + self.miner.set_author(author); + } + + /// Set the extra_data that we will seal blocks with. + pub fn set_extra_data(&self, extra_data: Bytes) { + self.miner.set_extra_data(extra_data); + } + + pub fn import_transactions(&self, transactions: Vec) { + let chain = self.chain.deref(); + let fetch_latest_nonce = |a : &Address| chain.nonce(a); + + self.miner.import_transactions(transactions, fetch_latest_nonce); + } + + pub fn chain_new_blocks(&self, good: &[H256], bad: &[H256], retracted: &[H256]) { + let mut chain = self.chain.deref(); + self.miner.chain_new_blocks(chain, good, bad, retracted); + } +} diff --git a/miner/src/miner.rs b/miner/src/miner.rs new file mode 100644 index 000000000..1a48d5288 --- /dev/null +++ b/miner/src/miner.rs @@ -0,0 +1,149 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::*; +use std::sync::atomic::AtomicBool; +use rayon::prelude::*; +use ethcore::views::{HeaderView, BlockView}; +use ethcore::header::{BlockNumber, Header as BlockHeader}; +use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo}; +use ethcore::block::*; +use ethcore::error::*; +use ethcore::transaction::SignedTransaction; +use transaction_queue::TransactionQueue; + +pub struct Miner { + /// Transactions Queue + transaction_queue: Mutex, + + // for sealing... + sealing_enabled: AtomicBool, + sealing_block: Mutex>, + author: RwLock
, + extra_data: RwLock, +} + +impl Miner { + pub fn new() -> Miner { + Miner { + transaction_queue: Mutex::new(TransactionQueue::new()), + sealing_enabled: AtomicBool::new(false), + sealing_block: Mutex::new(None), + author: RwLock::new(Address::new()), + extra_data: RwLock::new(Vec::new()), + } + } + + pub fn import_transactions(&self, transactions: Vec, fetch_nonce: T) + where T: Fn(&Address) -> U256 { + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.add_all(transactions, fetch_nonce); + } + + /// Get the author that we will seal blocks as. + pub fn author(&self) -> Address { + self.author.read().unwrap().clone() + } + + /// Set the author that we will seal blocks as. + pub fn set_author(&self, author: Address) { + *self.author.write().unwrap() = author; + } + + /// Get the extra_data that we will seal blocks wuth. + pub fn extra_data(&self) -> Bytes { + self.extra_data.read().unwrap().clone() + } + + /// Set the extra_data that we will seal blocks with. + pub fn set_extra_data(&self, extra_data: Bytes) { + *self.extra_data.write().unwrap() = extra_data; + } + + /// New chain head event. Restart mining operation. + fn prepare_sealing(&self, chain: &BlockChainClient) { + let b = chain.prepare_sealing(self.author.read().unwrap().clone(), self.extra_data.read().unwrap().clone()); + *self.sealing_block.lock().unwrap() = b; + } + + /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. + pub fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { + if self.sealing_block.lock().unwrap().is_none() { + self.sealing_enabled.store(true, atomic::Ordering::Relaxed); + // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. + self.prepare_sealing(chain); + } + &self.sealing_block + } + + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + pub fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { + let mut maybe_b = self.sealing_block.lock().unwrap(); + match *maybe_b { + Some(ref b) if b.hash() == pow_hash => {} + _ => { return Err(Error::PowHashInvalid); } + } + + let b = maybe_b.take(); + match chain.try_seal(b.unwrap(), seal) { + Err(old) => { + *maybe_b = Some(old); + Err(Error::PowInvalid) + } + Ok(sealed) => { + // TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice. + try!(chain.import_block(sealed.rlp_bytes())); + Ok(()) + } + } + } + + /// called when block is imported to chain, updates transactions queue and propagates the blocks + pub fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]) { + fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { + let block = chain + .block(BlockId::Hash(hash.clone())) + // Client should send message after commit to db and inserting to chain. + .expect("Expected in-chain blocks."); + let block = BlockView::new(&block); + block.transactions() + } + + { + let good = good.par_iter().map(|h| fetch_transactions(chain, h)); + let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); + + good.for_each(|txs| { + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); + transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); + }); + bad.for_each(|txs| { + // populate sender + for tx in &txs { + let _sender = tx.sender(); + } + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.add_all(txs, |a| chain.nonce(a)); + }); + } + + if self.sealing_enabled.load(atomic::Ordering::Relaxed) { + self.prepare_sealing(chain); + } + } +} diff --git a/sync/src/transaction_queue.rs b/miner/src/transaction_queue.rs similarity index 100% rename from sync/src/transaction_queue.rs rename to miner/src/transaction_queue.rs diff --git a/parity/main.rs b/parity/main.rs index 43b0504f1..ef088ab5b 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -24,6 +24,7 @@ extern crate rustc_serialize; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; +extern crate ethminer; #[macro_use] extern crate log as rlog; extern crate env_logger; @@ -49,6 +50,7 @@ use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethsync::{EthSync, SyncConfig}; +use ethminer::{EthMiner}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; @@ -79,6 +81,7 @@ Protocol Options: --networkid INDEX Override the network identifier from the chain we are on. --archive Client should not prune the state/storage trie. -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] + --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --identity NAME Specify your node's name. Networking Options: @@ -107,13 +110,13 @@ API and Console Options: Sealing/Mining Options: --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. - --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. + --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. Memory Footprint Options: --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. --queue-max-size BYTES Specify the maximum size of memory to use for block queue [default: 52428800]. - --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with + --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with other cache options (geth-compatible). Miscellaneous Options: @@ -129,7 +132,7 @@ struct Args { arg_enode: Vec, flag_chain: String, flag_testnet: bool, - flag_db_path: String, + flag_datadir: String, flag_networkid: Option, flag_identity: String, flag_cache: Option, @@ -189,7 +192,7 @@ fn setup_log(init: &Option) { } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) { +fn setup_rpc_server(client: Arc, sync: Arc, miner: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) { use rpc::v1::*; let mut server = rpc::HttpServer::new(1); @@ -198,7 +201,7 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_dom "web3" => server.add_delegate(Web3Client::new().to_delegate()), "net" => server.add_delegate(NetClient::new(&sync).to_delegate()), "eth" => { - server.add_delegate(EthClient::new(&client, &sync).to_delegate()); + server.add_delegate(EthClient::new(&client, &sync, &miner).to_delegate()); server.add_delegate(EthFilterClient::new(&client).to_delegate()); } _ => { @@ -238,7 +241,7 @@ impl Configuration { } fn path(&self) -> String { - self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + self.args.flag_datadir.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } fn author(&self) -> Address { @@ -323,6 +326,32 @@ impl Configuration { ret } + fn client_config(&self) -> ClientConfig { + let mut client_config = ClientConfig::default(); + match self.args.flag_cache { + Some(mb) => { + client_config.blockchain.max_cache_size = mb * 1024 * 1024; + client_config.blockchain.pref_cache_size = client_config.blockchain.max_cache_size / 2; + } + None => { + client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; + client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; + } + } + client_config.prefer_journal = !self.args.flag_archive; + client_config.name = self.args.flag_identity.clone(); + client_config.queue.max_mem_use = self.args.flag_queue_max_size; + client_config + } + + fn sync_config(&self, spec: &Spec) -> SyncConfig { + let mut sync_config = SyncConfig::default(); + sync_config.network_id = self.args.flag_networkid.as_ref().map(|id| { + U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --networkid", id)) + }).unwrap_or(spec.network_id()); + sync_config + } + fn execute(&self) { if self.args.flag_version { print_version(); @@ -346,31 +375,19 @@ impl Configuration { let spec = self.spec(); let net_settings = self.net_settings(&spec); - let mut sync_config = SyncConfig::default(); - sync_config.network_id = self.args.flag_networkid.as_ref().map(|id| U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --networkid", id))).unwrap_or(spec.network_id()); + let sync_config = self.sync_config(&spec); // Build client - let mut client_config = ClientConfig::default(); - match self.args.flag_cache { - Some(mb) => { - client_config.blockchain.max_cache_size = mb * 1024 * 1024; - client_config.blockchain.pref_cache_size = client_config.blockchain.max_cache_size / 2; - } - None => { - client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; - client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; - } - } - client_config.prefer_journal = !self.args.flag_archive; - client_config.name = self.args.flag_identity.clone(); - client_config.queue.max_mem_use = self.args.flag_queue_max_size; - let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); - let client = service.client().clone(); - client.set_author(self.author()); - client.set_extra_data(self.extra_data()); + let mut service = ClientService::start(self.client_config(), spec, net_settings, &Path::new(&self.path())).unwrap(); + let client = service.client(); + + // Miner + let miner = EthMiner::new(client.clone()); + miner.set_author(self.author()); + miner.set_extra_data(self.extra_data()); // Sync - let sync = EthSync::register(service.network(), sync_config, client); + let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); // Setup rpc if self.args.flag_jsonrpc || self.args.flag_rpc { @@ -382,7 +399,7 @@ impl Configuration { let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect()); + setup_rpc_server(service.client(), sync.clone(), miner.clone(), &url, cors, apis.split(",").collect()); } // Register IO handler diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index bfdf8f2d3..f6d468f47 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,6 +18,7 @@ ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } +ethminer = { path = "../miner" } clippy = { version = "0.0.44", optional = true } rustc-serialize = "0.3" transient-hashmap = "0.1" diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 0653a0c33..299084a6d 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -27,6 +27,7 @@ extern crate jsonrpc_http_server; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; +extern crate ethminer; extern crate transient_hashmap; use self::jsonrpc_core::{IoHandler, IoDelegate}; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 7113c55b1..11c6fe8d0 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -18,6 +18,7 @@ use std::collections::HashMap; use std::sync::{Arc, Weak, Mutex, RwLock}; use ethsync::{EthSync, SyncState}; +use ethminer::{EthMiner}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; @@ -36,15 +37,17 @@ use v1::helpers::{PollFilter, PollManager}; pub struct EthClient { client: Weak, sync: Weak, + miner: Weak, hashrates: RwLock>, } impl EthClient { /// Creates new EthClient. - pub fn new(client: &Arc, sync: &Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc, miner: &Arc) -> Self { EthClient { client: Arc::downgrade(client), sync: Arc::downgrade(sync), + miner: Arc::downgrade(miner), hashrates: RwLock::new(HashMap::new()), } } @@ -220,8 +223,8 @@ impl Eth for EthClient { fn work(&self, params: Params) -> Result { match params { Params::None => { - let c = take_weak!(self.client); - let u = c.sealing_block().lock().unwrap(); + let miner = take_weak!(self.miner); + let u = miner.sealing_block().lock().unwrap(); match *u { Some(ref b) => { let pow_hash = b.hash(); @@ -239,9 +242,9 @@ impl Eth for EthClient { fn submit_work(&self, params: Params) -> Result { from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { // trace!("Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash); - let c = take_weak!(self.client); + let miner = take_weak!(self.miner); let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; - let r = c.submit_seal(pow_hash, seal); + let r = miner.submit_seal(pow_hash, seal); to_value(&r.is_ok()) }) } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 0097cd47e..748065deb 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,15 +10,14 @@ authors = ["Ethcore , + /// Miner + miner: Arc, } type RlpResponseResult = Result, PacketDecodeError>; impl ChainSync { /// Create a new instance of syncing strategy. - pub fn new(config: SyncConfig) -> ChainSync { + pub fn new(config: SyncConfig, miner: Arc) -> ChainSync { ChainSync { state: SyncState::NotSynced, starting_block: 0, @@ -239,7 +238,7 @@ impl ChainSync { last_sent_block_number: 0, max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, - transaction_queue: Mutex::new(TransactionQueue::new()), + miner: miner, } } @@ -298,7 +297,6 @@ impl ChainSync { self.starting_block = 0; self.highest_block = None; self.have_common_block = false; - self.transaction_queue.lock().unwrap().clear(); self.starting_block = io.chain().chain_info().best_block_number; self.state = SyncState::NotSynced; } @@ -927,16 +925,15 @@ impl ChainSync { } /// Called when peer sends us new transactions fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { - let chain = io.chain(); let item_count = r.item_count(); trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count); - let fetch_latest_nonce = |a : &Address| chain.nonce(a); - let mut transaction_queue = self.transaction_queue.lock().unwrap(); + let mut transactions = Vec::with_capacity(item_count); for i in 0..item_count { let tx: SignedTransaction = try!(r.val_at(i)); - transaction_queue.add(tx, &fetch_latest_nonce); + transactions.push(tx); } + self.miner.import_transactions(transactions); Ok(()) } @@ -1263,38 +1260,9 @@ impl ChainSync { self.check_resume(io); } - /// called when block is imported to chain, updates transactions queue and propagates the blocks - pub fn chain_new_blocks(&mut self, io: &mut SyncIo, good: &[H256], bad: &[H256], _retracted: &[H256]) { - fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { - let block = chain - .block(BlockId::Hash(hash.clone())) - // Client should send message after commit to db and inserting to chain. - .expect("Expected in-chain blocks."); - let block = BlockView::new(&block); - block.transactions() - } - - - { - let chain = io.chain(); - let good = good.par_iter().map(|h| fetch_transactions(chain, h)); - let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); - - good.for_each(|txs| { - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); - transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); - }); - bad.for_each(|txs| { - // populate sender - for tx in &txs { - let _sender = tx.sender(); - } - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(txs, |a| chain.nonce(a)); - }); - } - + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, good: &[H256], bad: &[H256], retracted: &[H256]) { + // notify miner + self.miner.chain_new_blocks(good, bad, retracted); // Propagate latests blocks self.propagate_latest_blocks(io); // TODO [todr] propagate transactions? diff --git a/sync/src/lib.rs b/sync/src/lib.rs index b5869642c..0d6044135 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -51,27 +51,27 @@ extern crate log; #[macro_use] extern crate ethcore_util as util; extern crate ethcore; +extern crate ethminer; extern crate env_logger; extern crate time; extern crate rand; -extern crate rayon; #[macro_use] extern crate heapsize; use std::ops::*; use std::sync::*; -use ethcore::client::Client; use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId}; use util::TimerToken; use util::{U256, ONE_U256}; -use chain::ChainSync; +use ethcore::client::Client; use ethcore::service::SyncMessage; +use ethminer::EthMiner; use io::NetSyncIo; +use chain::ChainSync; mod chain; mod io; mod range_collection; -mod transaction_queue; #[cfg(test)] mod tests; @@ -105,10 +105,10 @@ pub use self::chain::{SyncStatus, SyncState}; impl EthSync { /// Creates and register protocol with the network service - pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc) -> Arc { + pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc, miner: Arc) -> Arc { let sync = Arc::new(EthSync { chain: chain, - sync: RwLock::new(ChainSync::new(config)), + sync: RwLock::new(ChainSync::new(config, miner)), }); service.register_protocol(sync.clone(), "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler"); sync @@ -154,7 +154,7 @@ impl NetworkProtocolHandler for EthSync { fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { - SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted } => { + SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted} => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); self.sync.write().unwrap().chain_new_blocks(&mut sync_io, good, bad, retracted); }, From 84444c697ce69ac8bc3f1126b6d6987af3a2df6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 15:53:12 +0100 Subject: [PATCH 430/753] Adding ethminer to dev/ci files --- .travis.yml | 7 ++++--- Cargo.toml | 2 +- cov.sh | 23 +++++++++++++++++------ doc.sh | 9 ++++++++- hook.sh | 2 +- rpc/Cargo.toml | 2 +- test.sh | 3 ++- 7 files changed, 34 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7213b8f09..48487e0d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,11 +14,11 @@ matrix: - rust: nightly include: - rust: stable - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: beta - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: nightly - env: FEATURES="--features travis-nightly" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-nightly" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: apt: true directories: @@ -51,6 +51,7 @@ after_success: | ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && + ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethminer-* && ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && diff --git a/Cargo.toml b/Cargo.toml index 7e5bc334b..a501baaab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ number_prefix = "0.2" [features] default = ["rpc"] rpc = ["ethcore-rpc"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev"] travis-beta = ["ethcore/json-tests"] travis-nightly = ["ethcore/json-tests", "dev"] diff --git a/cov.sh b/cov.sh index a1fa29e46..d60ef223d 100755 --- a/cov.sh +++ b/cov.sh @@ -15,12 +15,23 @@ if ! type kcov > /dev/null; then exit 1 fi -cargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --no-run || exit $? +cargo test \ + -p ethash \ + -p ethcore-util \ + -p ethcore \ + -p ethsync \ + -p ethcore-rpc \ + -p parity \ + -p ethminer \ + --no-run || exit $? rm -rf target/coverage mkdir -p target/coverage -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethash-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethsync-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* + +EXCLUDE="~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests" +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethash-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethsync-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethminer-* xdg-open target/coverage/index.html diff --git a/doc.sh b/doc.sh index 2fd5ac20f..a5e5e2e13 100755 --- a/doc.sh +++ b/doc.sh @@ -1,4 +1,11 @@ #!/bin/sh # generate documentation only for partiy and ethcore libraries -cargo doc --no-deps --verbose -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity +cargo doc --no-deps --verbose \ + -p ethash \ + -p ethcore-util \ + -p ethcore \ + -p ethsync \ + -p ethcore-rpc \ + -p parity \ + -p ethminer diff --git a/hook.sh b/hook.sh index 106ffe4f0..313639640 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,3 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --features dev" > ./.git/hooks/pre-push +echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer --features dev" > ./.git/hooks/pre-push chmod +x ./.git/hooks/pre-push diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index f6d468f47..d0174be59 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -31,4 +31,4 @@ syntex = "0.29.0" [features] default = ["serde_codegen"] nightly = ["serde_macros"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethminer/dev"] diff --git a/test.sh b/test.sh index 0f5edb0d1..e1881a8ad 100755 --- a/test.sh +++ b/test.sh @@ -1,4 +1,5 @@ #!/bin/sh # Running Parity Full Test Sute -cargo test --features ethcore/json-tests $1 -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity +cargo test --features ethcore/json-tests $1 -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p +ethminer From 9acb36af871d8b0c84f3a48a4587e9d64ae68456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 16:23:32 +0100 Subject: [PATCH 431/753] Fixing tests compilation. Removing ethminer dependency on client --- ethcore/src/log_entry.rs | 2 +- ethcore/src/tests/client.rs | 17 ++++---------- miner/src/lib.rs | 46 ++++++------------------------------- miner/src/miner.rs | 19 ++++++++++++--- parity/main.rs | 2 +- rpc/src/v1/impls/eth.rs | 7 ++++-- sync/src/chain.rs | 21 +++++++++-------- sync/src/tests/helpers.rs | 12 +++++++++- 8 files changed, 58 insertions(+), 68 deletions(-) diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index a75e6fcc1..63d09b4f0 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -111,7 +111,7 @@ mod tests { let bloom = H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let log = LogEntry { - address: address, + address: address, topics: vec![], data: vec![] }; diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 001d1729b..d31a780e6 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -132,16 +132,9 @@ fn can_mine() { let dummy_blocks = get_good_dummy_block_seq(2); let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let client = client_result.reference(); - let b = client.sealing_block(); - let pow_hash = { - let u = b.lock().unwrap(); - match *u { - Some(ref b) => { - assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); - b.hash() - } - None => { panic!(); } - } - }; - assert!(client.submit_seal(pow_hash, vec![]).is_ok()); + + let b = client.prepare_sealing(Address::default(), vec![]).unwrap(); + + assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); + assert!(client.try_seal(b, vec![]).is_ok()); } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index e8a50e9b5..ae6235393 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -29,58 +29,26 @@ extern crate rayon; mod miner; mod transaction_queue; -use util::{Bytes, H256, Address}; use std::ops::*; use std::sync::*; -use util::TimerToken; -use ethcore::block::*; -use ethcore::error::*; -use ethcore::client::{Client, BlockChainClient}; -use ethcore::transaction::*; -use miner::Miner; +pub use miner::Miner; pub struct EthMiner { miner: Miner, - /// Shared blockchain client. TODO: this should evetually become an IPC endpoint - chain: Arc, } impl EthMiner { /// Creates and register protocol with the network service - pub fn new(chain: Arc) -> Arc { + pub fn new() -> Arc { Arc::new(EthMiner { miner: Miner::new(), - chain: chain, }) } +} +impl Deref for EthMiner { + type Target = Miner; - pub fn sealing_block(&self) -> &Mutex> { - self.miner.sealing_block(self.chain.deref()) - } - - pub fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { - self.miner.submit_seal(self.chain.deref(), pow_hash, seal) - } - - /// Set the author that we will seal blocks as. - pub fn set_author(&self, author: Address) { - self.miner.set_author(author); - } - - /// Set the extra_data that we will seal blocks with. - pub fn set_extra_data(&self, extra_data: Bytes) { - self.miner.set_extra_data(extra_data); - } - - pub fn import_transactions(&self, transactions: Vec) { - let chain = self.chain.deref(); - let fetch_latest_nonce = |a : &Address| chain.nonce(a); - - self.miner.import_transactions(transactions, fetch_latest_nonce); - } - - pub fn chain_new_blocks(&self, good: &[H256], bad: &[H256], retracted: &[H256]) { - let mut chain = self.chain.deref(); - self.miner.chain_new_blocks(chain, good, bad, retracted); + fn deref(&self) -> &Self::Target { + &self.miner } } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 1a48d5288..76130b261 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -23,7 +23,7 @@ use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo}; use ethcore::block::*; use ethcore::error::*; use ethcore::transaction::SignedTransaction; -use transaction_queue::TransactionQueue; +use transaction_queue::{TransactionQueue, TransactionQueueStatus}; pub struct Miner { /// Transactions Queue @@ -36,6 +36,11 @@ pub struct Miner { extra_data: RwLock, } +pub struct MinerStatus { + pub transaction_queue_pending: usize, + pub transaction_queue_future: usize, +} + impl Miner { pub fn new() -> Miner { Miner { @@ -47,6 +52,14 @@ impl Miner { } } + pub fn status(&self) -> MinerStatus { + let status = self.transaction_queue.lock().unwrap().status(); + MinerStatus { + transaction_queue_pending: status.pending, + transaction_queue_future: status.future, + } + } + pub fn import_transactions(&self, transactions: Vec, fetch_nonce: T) where T: Fn(&Address) -> U256 { let mut transaction_queue = self.transaction_queue.lock().unwrap(); @@ -55,7 +68,7 @@ impl Miner { /// Get the author that we will seal blocks as. pub fn author(&self) -> Address { - self.author.read().unwrap().clone() + *self.author.read().unwrap() } /// Set the author that we will seal blocks as. @@ -75,7 +88,7 @@ impl Miner { /// New chain head event. Restart mining operation. fn prepare_sealing(&self, chain: &BlockChainClient) { - let b = chain.prepare_sealing(self.author.read().unwrap().clone(), self.extra_data.read().unwrap().clone()); + let b = chain.prepare_sealing(*self.author.read().unwrap(), self.extra_data.read().unwrap().clone()); *self.sealing_block.lock().unwrap() = b; } diff --git a/parity/main.rs b/parity/main.rs index ef088ab5b..a0bc87a03 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -382,7 +382,7 @@ impl Configuration { let client = service.client(); // Miner - let miner = EthMiner::new(client.clone()); + let miner = EthMiner::new(); miner.set_author(self.author()); miner.set_extra_data(self.extra_data()); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 11c6fe8d0..46d875c99 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -17,6 +17,7 @@ //! Eth rpc implementation. use std::collections::HashMap; use std::sync::{Arc, Weak, Mutex, RwLock}; +use std::ops::Deref; use ethsync::{EthSync, SyncState}; use ethminer::{EthMiner}; use jsonrpc_core::*; @@ -224,7 +225,8 @@ impl Eth for EthClient { match params { Params::None => { let miner = take_weak!(self.miner); - let u = miner.sealing_block().lock().unwrap(); + let client = take_weak!(self.client); + let u = miner.sealing_block(client.deref()).lock().unwrap(); match *u { Some(ref b) => { let pow_hash = b.hash(); @@ -243,8 +245,9 @@ impl Eth for EthClient { from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { // trace!("Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash); let miner = take_weak!(self.miner); + let client = take_weak!(self.client); let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; - let r = miner.submit_seal(pow_hash, seal); + let r = miner.submit_seal(client.deref(), pow_hash, seal); to_value(&r.is_ok()) }) } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index d3277eccc..c607f53b1 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -31,7 +31,7 @@ use util::*; use std::mem::{replace}; -use ethcore::views::{HeaderView, BlockView}; +use ethcore::views::{HeaderView}; use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo}; use range_collection::{RangeCollection, ToUsize, FromUsize}; @@ -933,7 +933,9 @@ impl ChainSync { let tx: SignedTransaction = try!(r.val_at(i)); transactions.push(tx); } - self.miner.import_transactions(transactions); + let chain = io.chain(); + let fetch_nonce = |a: &Address| chain.nonce(a); + self.miner.import_transactions(transactions, fetch_nonce); Ok(()) } @@ -1262,7 +1264,7 @@ impl ChainSync { pub fn chain_new_blocks(&mut self, io: &mut SyncIo, good: &[H256], bad: &[H256], retracted: &[H256]) { // notify miner - self.miner.chain_new_blocks(good, bad, retracted); + self.miner.chain_new_blocks(io.chain(), good, bad, retracted); // Propagate latests blocks self.propagate_latest_blocks(io); // TODO [todr] propagate transactions? @@ -1279,6 +1281,7 @@ mod tests { use super::{PeerInfo, PeerAsking}; use ethcore::header::*; use ethcore::client::*; + use ethminer::EthMiner; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); @@ -1388,7 +1391,7 @@ mod tests { } fn dummy_sync_with_peer(peer_latest_hash: H256) -> ChainSync { - let mut sync = ChainSync::new(SyncConfig::default()); + let mut sync = ChainSync::new(SyncConfig::default(), EthMiner::new()); sync.peers.insert(0, PeerInfo { protocol_version: 0, @@ -1610,14 +1613,14 @@ mod tests { // when sync.chain_new_blocks(&mut io, &[], &good_blocks, &[]); - assert_eq!(sync.transaction_queue.lock().unwrap().status().future, 0); - assert_eq!(sync.transaction_queue.lock().unwrap().status().pending, 1); + assert_eq!(sync.miner.status().transaction_queue_future, 0); + assert_eq!(sync.miner.status().transaction_queue_pending, 1); sync.chain_new_blocks(&mut io, &good_blocks, &retracted_blocks, &[]); // then - let status = sync.transaction_queue.lock().unwrap().status(); - assert_eq!(status.pending, 1); - assert_eq!(status.future, 0); + let status = sync.miner.status(); + assert_eq!(status.transaction_queue_pending, 1); + assert_eq!(status.transaction_queue_future, 0); } #[test] diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index d01dba0b2..37ee862b5 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -17,7 +17,9 @@ use util::*; use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId, BlockQueueInfo}; use ethcore::header::{Header as BlockHeader, BlockNumber}; +use ethcore::block::*; use ethcore::error::*; +use ethminer::EthMiner; use io::SyncIo; use chain::ChainSync; use ::SyncConfig; @@ -308,6 +310,14 @@ impl BlockChainClient for TestBlockChainClient { best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, } } + + fn prepare_sealing(&self, author: Address, extra_data: Bytes) -> Option { + unimplemented!() + } + + fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result { + unimplemented!() + } } pub struct TestIo<'p> { @@ -382,7 +392,7 @@ impl TestNet { for _ in 0..n { net.peers.push(TestPeer { chain: TestBlockChainClient::new(), - sync: ChainSync::new(SyncConfig::default()), + sync: ChainSync::new(SyncConfig::default(), EthMiner::new()), queue: VecDeque::new(), }); } From 49f1834ffb97244f0aaf404d86c0bdaaf226c9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 16:40:35 +0100 Subject: [PATCH 432/753] Fixing travis yml whitespace --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48487e0d3..0c614ca5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,11 +14,11 @@ matrix: - rust: nightly include: - rust: stable - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: beta - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - rust: nightly - env: FEATURES="--features travis-nightly" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-nightly" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: apt: true directories: From b2fc077f8c6a8a28ca0f14e975107b7431887f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 8 Mar 2016 16:42:30 +0100 Subject: [PATCH 433/753] Fixing CLI parameters --- parity/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 43b0504f1..ceb58e31e 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -79,6 +79,7 @@ Protocol Options: --networkid INDEX Override the network identifier from the chain we are on. --archive Client should not prune the state/storage trie. -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] + --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --identity NAME Specify your node's name. Networking Options: @@ -113,7 +114,7 @@ Memory Footprint Options: --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. --queue-max-size BYTES Specify the maximum size of memory to use for block queue [default: 52428800]. - --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with + --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with other cache options (geth-compatible). Miscellaneous Options: @@ -129,7 +130,7 @@ struct Args { arg_enode: Vec, flag_chain: String, flag_testnet: bool, - flag_db_path: String, + flag_datadir: String, flag_networkid: Option, flag_identity: String, flag_cache: Option, @@ -238,7 +239,7 @@ impl Configuration { } fn path(&self) -> String { - self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + self.args.flag_datadir.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } fn author(&self) -> Address { From a069e890ba52cf5242cf4492266b1d638a138d74 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 8 Mar 2016 19:14:43 +0100 Subject: [PATCH 434/753] Replaced --archive option with --pruning --- parity/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index ceb58e31e..2d7bd8bab 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -77,7 +77,7 @@ Protocol Options: or olympic, frontier, homestead, mainnet, morden, or testnet [default: homestead]. --testnet Equivalent to --chain testnet (geth-compatible). --networkid INDEX Override the network identifier from the chain we are on. - --archive Client should not prune the state/storage trie. + --pruning Enable state/storage trie pruning. -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --identity NAME Specify your node's name. @@ -135,7 +135,7 @@ struct Args { flag_identity: String, flag_cache: Option, flag_keys_path: String, - flag_archive: bool, + flag_pruning: bool, flag_no_bootstrap: bool, flag_listen_address: String, flag_public_address: Option, @@ -362,7 +362,7 @@ impl Configuration { client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; } } - client_config.prefer_journal = !self.args.flag_archive; + client_config.prefer_journal = self.args.flag_pruning; client_config.name = self.args.flag_identity.clone(); client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); From 389779d86ca0d714cff0a8861a0f9ac58219d6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 00:05:47 +0100 Subject: [PATCH 435/753] Updating benchmarks to avoid inlining/optimizing --- util/benches/bigint.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs index 80c4ce1d8..3f4164d18 100644 --- a/util/benches/bigint.rs +++ b/util/benches/bigint.rs @@ -50,9 +50,16 @@ fn u256_sub(b: &mut Bencher) { fn u512_sub(b: &mut Bencher) { b.iter(|| { let n = black_box(10000); - (0..n).fold(U512([rand::random::(), rand::random::(), rand::random::(), rand::random::(), - rand::random::(), rand::random::(), rand::random::(), rand::random::()]), - |old, new| { old.overflowing_sub(U512([0, 0, 0, 0, 0, 0, 0, new])).0 }) + (0..n).fold( + U512([ + rand::random::(), rand::random::(), rand::random::(), rand::random::(), + rand::random::(), rand::random::(), rand::random::(), rand::random::() + ]), + |old, new| { + let p = new % 2; + old.overflowing_sub(U512([p, p, p, p, p, p, p, new])).0 + } + ) }); } From f84d40734d372aa2338df55dc0ad44c4d97650b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 10:26:51 +0100 Subject: [PATCH 436/753] Validating sender before importing to queuue --- sync/src/chain.rs | 4 +- sync/src/transaction_queue.rs | 140 +++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 57 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index a41b06904..8cf1beea1 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -935,7 +935,7 @@ impl ChainSync { let mut transaction_queue = self.transaction_queue.lock().unwrap(); for i in 0..item_count { let tx: SignedTransaction = try!(r.val_at(i)); - transaction_queue.add(tx, &fetch_latest_nonce); + let _ = transaction_queue.add(tx, &fetch_latest_nonce); } Ok(()) } @@ -1291,7 +1291,7 @@ impl ChainSync { let _sender = tx.sender(); } let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(txs, |a| chain.nonce(a)); + let _ = transaction_queue.add_all(txs, |a| chain.nonce(a)); }); } diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 3e0d931b5..39ad29894 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -24,6 +24,7 @@ use util::numbers::{Uint, U256}; use util::hash::{Address, H256}; use util::table::*; use ethcore::transaction::*; +use ethcore::error::Error; #[derive(Clone, Debug)] @@ -82,10 +83,11 @@ struct VerifiedTransaction { transaction: SignedTransaction } impl VerifiedTransaction { - fn new(transaction: SignedTransaction) -> Self { - VerifiedTransaction { + fn new(transaction: SignedTransaction) -> Result { + try!(transaction.sender()); + Ok(VerifiedTransaction { transaction: transaction - } + }) } fn hash(&self) -> H256 { @@ -148,6 +150,8 @@ impl TransactionSet { } } +// Will be used when rpc merged +#[allow(dead_code)] #[derive(Debug)] /// Current status of the queue pub struct TransactionQueueStatus { @@ -196,6 +200,8 @@ impl TransactionQueue { } } + // Will be used when rpc merged + #[allow(dead_code)] /// Returns current status for this queue pub fn status(&self) -> TransactionQueueStatus { TransactionQueueStatus { @@ -205,17 +211,19 @@ impl TransactionQueue { } /// Adds all signed transactions to queue to be verified and imported - pub fn add_all(&mut self, txs: Vec, fetch_nonce: T) + pub fn add_all(&mut self, txs: Vec, fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256 { for tx in txs.into_iter() { - self.add(tx, &fetch_nonce); + try!(self.add(tx, &fetch_nonce)); } + Ok(()) } /// Add signed transaction to queue to be verified and imported - pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) + pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) -> Result<(), Error> where T: Fn(&Address) -> U256 { - self.import_tx(VerifiedTransaction::new(tx), fetch_nonce); + self.import_tx(try!(VerifiedTransaction::new(tx)), fetch_nonce); + Ok(()) } /// Removes all transactions identified by hashes given in slice @@ -299,7 +307,8 @@ impl TransactionQueue { self.future.enforce_limit(&mut self.by_hash); } - + // Will be used when mining merged + #[allow(dead_code)] /// Returns top transactions from the queue pub fn top_transactions(&self, size: usize) -> Vec { self.current.by_priority @@ -407,13 +416,8 @@ impl TransactionQueue { #[cfg(test)] mod test { extern crate rustc_serialize; - use self::rustc_serialize::hex::FromHex; - use std::ops::Deref; - use std::collections::{HashMap, BTreeSet}; - use util::crypto::KeyPair; - use util::numbers::{U256, Uint}; - use util::hash::{Address}; use util::table::*; + use util::*; use ethcore::transaction::*; use super::*; use super::{TransactionSet, TransactionOrder, VerifiedTransaction}; @@ -457,12 +461,12 @@ mod test { limit: 1 }; let (tx1, tx2) = new_txs(U256::from(1)); - let tx1 = VerifiedTransaction::new(tx1); - let tx2 = VerifiedTransaction::new(tx2); + let tx1 = VerifiedTransaction::new(tx1).unwrap(); + let tx2 = VerifiedTransaction::new(tx2).unwrap(); let mut by_hash = { let mut x = HashMap::new(); - let tx1 = VerifiedTransaction::new(tx1.transaction.clone()); - let tx2 = VerifiedTransaction::new(tx2.transaction.clone()); + let tx1 = VerifiedTransaction::new(tx1.transaction.clone()).unwrap(); + let tx2 = VerifiedTransaction::new(tx2.transaction.clone()).unwrap(); x.insert(tx1.hash(), tx1); x.insert(tx2.hash(), tx2); x @@ -496,13 +500,39 @@ mod test { let tx = new_tx(); // when - txq.add(tx, &default_nonce); + let res = txq.add(tx, &default_nonce); // then + assert!(res.is_ok()); let stats = txq.status(); assert_eq!(stats.pending, 1); } + #[test] + fn should_reject_incorectly_signed_transaction() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_unsigned_tx(U256::from(123)); + let stx = { + let mut s = RlpStream::new_list(9); + s.append(&tx.nonce); + s.append(&tx.gas_price); + s.append(&tx.gas); + s.append_empty_data(); // action=create + s.append(&tx.value); + s.append(&tx.data); + s.append(&0u64); // v + s.append(&U256::zero()); // r + s.append(&U256::zero()); // s + decode(s.as_raw()) + }; + // when + let res = txq.add(stx, &default_nonce); + + // then + assert!(res.is_err()); + } + #[test] fn should_import_txs_from_same_sender() { // given @@ -511,8 +541,8 @@ mod test { let (tx, tx2) = new_txs(U256::from(1)); // when - txq.add(tx.clone(), &default_nonce); - txq.add(tx2.clone(), &default_nonce); + txq.add(tx.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); // then let top = txq.top_transactions(5); @@ -529,8 +559,8 @@ mod test { let (tx, tx2) = new_txs(U256::from(2)); // when - txq.add(tx.clone(), &default_nonce); - txq.add(tx2.clone(), &default_nonce); + txq.add(tx.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); // then let stats = txq.status(); @@ -551,13 +581,13 @@ mod test { let tx1 = new_unsigned_tx(U256::from(124)).sign(&secret); let tx2 = new_unsigned_tx(U256::from(125)).sign(&secret); - txq.add(tx, &default_nonce); + txq.add(tx, &default_nonce).unwrap(); assert_eq!(txq.status().pending, 1); - txq.add(tx2, &default_nonce); + txq.add(tx2, &default_nonce).unwrap(); assert_eq!(txq.status().future, 1); // when - txq.add(tx1, &default_nonce); + txq.add(tx1, &default_nonce).unwrap(); // then let stats = txq.status(); @@ -570,8 +600,8 @@ mod test { // given let mut txq2 = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(3)); - txq2.add(tx.clone(), &default_nonce); - txq2.add(tx2.clone(), &default_nonce); + txq2.add(tx.clone(), &default_nonce).unwrap(); + txq2.add(tx2.clone(), &default_nonce).unwrap(); assert_eq!(txq2.status().pending, 1); assert_eq!(txq2.status().future, 1); @@ -592,10 +622,10 @@ mod test { let mut txq = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(1)); let tx3 = new_tx(); - txq.add(tx2.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().future, 1); - txq.add(tx3.clone(), &default_nonce); - txq.add(tx.clone(), &default_nonce); + txq.add(tx3.clone(), &default_nonce).unwrap(); + txq.add(tx.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().pending, 3); // when @@ -614,8 +644,8 @@ mod test { let (tx, tx2) = new_txs(U256::one()); // add - txq.add(tx2.clone(), &default_nonce); - txq.add(tx.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce).unwrap(); + txq.add(tx.clone(), &default_nonce).unwrap(); let stats = txq.status(); assert_eq!(stats.pending, 2); @@ -632,11 +662,11 @@ mod test { // given let mut txq = TransactionQueue::with_limits(1, 1); let (tx, tx2) = new_txs(U256::one()); - txq.add(tx.clone(), &default_nonce); + txq.add(tx.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().pending, 1); // when - txq.add(tx2.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce).unwrap(); // then let t = txq.top_transactions(2); @@ -650,14 +680,14 @@ mod test { let mut txq = TransactionQueue::with_limits(10, 1); let (tx1, tx2) = new_txs(U256::from(4)); let (tx3, tx4) = new_txs(U256::from(4)); - txq.add(tx1.clone(), &default_nonce); - txq.add(tx3.clone(), &default_nonce); + txq.add(tx1.clone(), &default_nonce).unwrap(); + txq.add(tx3.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().pending, 2); // when - txq.add(tx2.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().future, 1); - txq.add(tx4.clone(), &default_nonce); + txq.add(tx4.clone(), &default_nonce).unwrap(); // then assert_eq!(txq.status().future, 1); @@ -671,7 +701,7 @@ mod test { let fetch_last_nonce = |_a: &Address| last_nonce; // when - txq.add(tx, &fetch_last_nonce); + txq.add(tx, &fetch_last_nonce).unwrap(); // then let stats = txq.status(); @@ -685,12 +715,12 @@ mod test { let nonce = |a: &Address| default_nonce(a) + U256::one(); let mut txq = TransactionQueue::new(); let (_tx1, tx2) = new_txs(U256::from(1)); - txq.add(tx2.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().future, 1); assert_eq!(txq.status().pending, 0); // when - txq.add(tx2.clone(), &nonce); + txq.add(tx2.clone(), &nonce).unwrap(); // then let stats = txq.status(); @@ -703,15 +733,15 @@ mod test { // given let mut txq = TransactionQueue::new(); let (tx1, tx2) = new_txs(U256::from(1)); - txq.add(tx1.clone(), &default_nonce); - txq.add(tx2.clone(), &default_nonce); + txq.add(tx1.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().pending, 2); // when txq.remove(&tx1.hash(), &default_nonce); assert_eq!(txq.status().pending, 0); assert_eq!(txq.status().future, 1); - txq.add(tx1.clone(), &default_nonce); + txq.add(tx1.clone(), &default_nonce).unwrap(); // then let stats = txq.status(); @@ -726,10 +756,10 @@ mod test { let mut txq = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(1)); let tx3 = new_tx(); - txq.add(tx2.clone(), &default_nonce); + txq.add(tx2.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().future, 1); - txq.add(tx3.clone(), &default_nonce); - txq.add(tx.clone(), &default_nonce); + txq.add(tx3.clone(), &default_nonce).unwrap(); + txq.add(tx.clone(), &default_nonce).unwrap(); assert_eq!(txq.status().pending, 3); // when @@ -754,8 +784,8 @@ mod test { }; // when - txq.add(tx, &default_nonce); - txq.add(tx2, &default_nonce); + txq.add(tx, &default_nonce).unwrap(); + txq.add(tx2, &default_nonce).unwrap(); // then let stats = txq.status(); @@ -782,10 +812,10 @@ mod test { }; // when - txq.add(tx1, &default_nonce); - txq.add(tx2, &default_nonce); + txq.add(tx1, &default_nonce).unwrap(); + txq.add(tx2, &default_nonce).unwrap(); assert_eq!(txq.status().future, 1); - txq.add(tx0, &default_nonce); + txq.add(tx0, &default_nonce).unwrap(); // then let stats = txq.status(); @@ -801,8 +831,8 @@ mod test { let next_nonce = |a: &Address| default_nonce(a) + U256::one(); let mut txq = TransactionQueue::new(); let (tx1, tx2) = new_txs(U256::one()); - txq.add(tx1.clone(), &previous_nonce); - txq.add(tx2, &previous_nonce); + txq.add(tx1.clone(), &previous_nonce).unwrap(); + txq.add(tx2, &previous_nonce).unwrap(); assert_eq!(txq.status().future, 2); // when From b3fc16ed9a51e91736a26c7e95cf210399a70d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 11:32:23 +0100 Subject: [PATCH 437/753] Fixing bug in multiplication implementation --- util/bigint/src/uint.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 801c5f5bd..69aaa5809 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -407,7 +407,7 @@ macro_rules! uint_overflowing_mul_reg { let (b_u, b_l) = split(you[i]); for j in 0..$n_words { - if me[j] == 0 { + if me[j] == 0 && carry2 == 0 { continue; } @@ -1640,6 +1640,14 @@ mod tests { assert_eq!(U256::from(1u64) * U256::from(10u64), U256::from(10u64)); } + #[test] + pub fn uint256_mul2() { + let a = U512::from_str("10000000000000000fffffffffffffffe").unwrap(); + let b = U512::from_str("ffffffffffffffffffffffffffffffff").unwrap(); + + assert_eq!(a * b, U512::from_str("10000000000000000fffffffffffffffcffffffffffffffff0000000000000002").unwrap()); + } + #[test] pub fn uint256_overflowing_mul() { assert_eq!( From a1640dcf7205c2d47b017e2398c6fda03da889d6 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 9 Mar 2016 11:38:53 +0100 Subject: [PATCH 438/753] jsonrpc panic handle --- ethcore/src/block_queue.rs | 2 +- parity/main.rs | 34 +++++++++++++++++++++------------- rpc/src/lib.rs | 22 +++++++++++++++++----- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 490a17995..8f1105b8b 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -385,7 +385,7 @@ impl BlockQueue { } } - pub fn collect_garbage(&self) { + pub fn collect_garbage(&self) { { let mut verification = self.verification.lock().unwrap(); verification.unverified.shrink_to_fit(); diff --git a/parity/main.rs b/parity/main.rs index 605fb315d..94db8e706 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -43,7 +43,7 @@ use std::path::PathBuf; use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; -use util::panics::MayPanic; +use util::panics::{MayPanic, PanicHandler}; use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; @@ -151,7 +151,7 @@ fn setup_log(init: &Option) { } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_domain: &str) { +fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_domain: &str) -> Option> { use rpc::v1::*; let mut server = rpc::HttpServer::new(1); @@ -159,11 +159,12 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_dom server.add_delegate(EthClient::new(&client, &sync).to_delegate()); server.add_delegate(EthFilterClient::new(&client).to_delegate()); server.add_delegate(NetClient::new(&sync).to_delegate()); - server.start_async(url, cors_domain); + Some(server.start_async(url, cors_domain)) } #[cfg(not(feature = "rpc"))] -fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) { +fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) -> Option> { + None } fn print_version() { @@ -323,26 +324,28 @@ impl Configuration { // Sync let sync = EthSync::register(service.network(), sync_config, client); - // Setup rpc - if self.args.flag_jsonrpc { - setup_rpc_server(service.client(), sync.clone(), &self.args.flag_jsonrpc_url, &self.args.flag_jsonrpc_cors); - SocketAddr::from_str(&self.args.flag_jsonrpc_url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen address given with --jsonrpc-url. Should be of the form 'IP:port'.", self.args.flag_jsonrpc_url)); - } - // Register IO handler let io_handler = Arc::new(ClientIoHandler { client: service.client(), info: Default::default(), - sync: sync + sync: sync.clone(), }); service.io().register_handler(io_handler).expect("Error registering IO handler"); + // Setup rpc + let server_handler = if self.args.flag_jsonrpc { + SocketAddr::from_str(&self.args.flag_jsonrpc_url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen address given with --jsonrpc-url. Should be of the form 'IP:port'.", self.args.flag_jsonrpc_url)); + setup_rpc_server(service.client(), sync, &self.args.flag_jsonrpc_url, &self.args.flag_jsonrpc_cors) + } else { + None + }; + // Handle exit - wait_for_exit(&service); + wait_for_exit(&service, server_handler); } } -fn wait_for_exit(client_service: &ClientService) { +fn wait_for_exit(client_service: &ClientService, server_handler: Option>) { let exit = Arc::new(Condvar::new()); // Handle possible exits @@ -351,6 +354,11 @@ fn wait_for_exit(client_service: &ClientService) { let e = exit.clone(); client_service.on_panic(move |_reason| { e.notify_all(); }); + if let Some(handler) = server_handler { + let e = exit.clone(); + handler.on_panic(move |_reason| { e.notify_all(); }); + } + // Wait for signal let mutex = Mutex::new(()); let _ = exit.wait(mutex.lock().unwrap()).unwrap(); diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 0653a0c33..97a3a5fe5 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -29,6 +29,9 @@ extern crate ethcore; extern crate ethsync; extern crate transient_hashmap; +use std::sync::Arc; +use std::thread; +use util::panics::PanicHandler; use self::jsonrpc_core::{IoHandler, IoDelegate}; pub mod v1; @@ -36,7 +39,7 @@ pub mod v1; /// Http server. pub struct HttpServer { handler: IoHandler, - threads: usize + threads: usize, } impl HttpServer { @@ -44,7 +47,7 @@ impl HttpServer { pub fn new(threads: usize) -> HttpServer { HttpServer { handler: IoHandler::new(), - threads: threads + threads: threads, } } @@ -53,9 +56,18 @@ impl HttpServer { self.handler.add_delegate(delegate); } - /// Start server asynchronously in new thread - pub fn start_async(self, addr: &str, cors_domain: &str) { + /// Start server asynchronously in new thread and returns panic handler. + pub fn start_async(self, addr: &str, cors_domain: &str) -> Arc { + let addr = addr.to_owned(); + let cors_domain = cors_domain.to_owned(); + let panic_handler = PanicHandler::new_in_arc(); + let ph = panic_handler.clone(); let server = jsonrpc_http_server::Server::new(self.handler, self.threads); - server.start_async(addr, jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain.to_owned())) + thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { + ph.catch_panic(move || { + server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain)); + }).unwrap() + }).expect("Error while creating jsonrpc http thread"); + panic_handler } } From 79d2beb42aaeb1bec47031b55f723cedadf5d54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 11:50:35 +0100 Subject: [PATCH 439/753] Same bug in full_mul --- util/bigint/src/uint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 69aaa5809..698b12f42 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -1275,7 +1275,7 @@ impl U256 { let (b_u, b_l) = split(you[i]); for j in 0..4 { - if me[j] == 0 { + if me[j] == 0 && carry2 == 0 { continue; } From 5db84c32338bc6708dce3d299553531f27b68f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 12:54:07 +0100 Subject: [PATCH 440/753] Adding transactions to block --- ethcore/src/block.rs | 2 +- ethcore/src/client.rs | 35 +++++++++++++++++++++++++++++------ ethcore/src/service.rs | 2 ++ ethcore/src/tests/client.rs | 2 +- miner/src/miner.rs | 11 +++++++++-- sync/src/chain.rs | 4 ++++ sync/src/lib.rs | 4 ++++ sync/src/tests/helpers.rs | 4 ++-- 8 files changed, 52 insertions(+), 12 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 68f647e37..9ecd58e0a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -274,7 +274,7 @@ impl<'x> OpenBlock<'x> { s.block.base.header.note_dirty(); ClosedBlock { - block: s.block, + block: s.block, uncle_bytes: uncle_bytes, } } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index af1745ca8..fb69df757 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -32,7 +32,7 @@ use service::{NetSyncMessage, SyncMessage}; use env_info::LastHashes; use verification::*; use block::*; -use transaction::LocalizedTransaction; +use transaction::{LocalizedTransaction, SignedTransaction}; use extras::TransactionAddress; use filter::Filter; use log_entry::LocalizedLogEntry; @@ -185,7 +185,10 @@ pub trait BlockChainClient : Sync + Send { /// Returns logs matching given filter. fn logs(&self, filter: Filter) -> Vec; - fn prepare_sealing(&self, author: Address, extra_data: Bytes) -> Option; + /// Returns ClosedBlock prepared for sealing. + fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option; + + /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result; } @@ -417,6 +420,12 @@ impl Client where V: Verifier { } } + { + if self.chain_info().best_block_hash != original_best { + io.send(NetworkIoMessage::User(SyncMessage::NewChainHead)).unwrap(); + } + } + imported } @@ -477,7 +486,7 @@ impl BlockChainClient for Client where V: Verifier { block.try_seal(self.engine.deref().deref(), seal) } - fn prepare_sealing(&self, author: Address, extra_data: Bytes) -> Option { + fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option { let engine = self.engine.deref().deref(); let h = self.chain.read().unwrap().best_block_hash(); @@ -490,7 +499,9 @@ impl BlockChainClient for Client where V: Verifier { extra_data, ); - self.chain.read().unwrap().find_uncle_headers(&h, engine.maximum_uncle_age()) + // Add uncles + self.chain.read().unwrap() + .find_uncle_headers(&h, engine.maximum_uncle_age()) .unwrap() .into_iter() .take(engine.maximum_uncle_count()) @@ -498,10 +509,22 @@ impl BlockChainClient for Client where V: Verifier { b.push_uncle(h).unwrap(); }); - // TODO: push transactions. + // Add transactions + let block_number = b.block().header().number(); + for tx in transactions { + let import = b.push_transaction(tx, None); + if let Err(e) = import { + trace!("Error adding transaction to block: number={}. Error: {:?}", block_number, e); + } + } + // And close let b = b.close(); - trace!("Sealing: number={}, hash={}, diff={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); + trace!("Sealing: number={}, hash={}, diff={}", + b.block().header().number(), + b.hash(), + b.block().header().difficulty() + ); Some(b) } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 443d09e3b..11380d276 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -34,6 +34,8 @@ pub enum SyncMessage { /// Hashes of blocks that were removed from canonical chain retracted: Vec, }, + /// Best Block Hash in chain has been changed + NewChainHead, /// A block is ready BlockVerified, } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d31a780e6..ed0b02788 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -133,7 +133,7 @@ fn can_mine() { let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let client = client_result.reference(); - let b = client.prepare_sealing(Address::default(), vec![]).unwrap(); + let b = client.prepare_sealing(Address::default(), vec![], vec![]).unwrap(); assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); assert!(client.try_seal(b, vec![]).is_ok()); diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 76130b261..501f8c35c 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -87,8 +87,15 @@ impl Miner { } /// New chain head event. Restart mining operation. - fn prepare_sealing(&self, chain: &BlockChainClient) { - let b = chain.prepare_sealing(*self.author.read().unwrap(), self.extra_data.read().unwrap().clone()); + pub fn prepare_sealing(&self, chain: &BlockChainClient) { + let no_of_transactions = 128; + let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); + + let b = chain.prepare_sealing( + self.author(), + self.extra_data(), + transactions, + ); *self.sealing_block.lock().unwrap() = b; } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index c607f53b1..2669b71e2 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1270,6 +1270,10 @@ impl ChainSync { // TODO [todr] propagate transactions? } + pub fn chain_new_head(&mut self, io: &mut SyncIo) { + self.miner.prepare_sealing(io.chain()); + } + } #[cfg(test)] diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 0d6044135..be01d2b7b 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -158,6 +158,10 @@ impl NetworkProtocolHandler for EthSync { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); self.sync.write().unwrap().chain_new_blocks(&mut sync_io, good, bad, retracted); }, + SyncMessage::NewChainHead => { + let mut sync_io = NetSyncIo::new(io, self.chain.deref()); + self.sync.write().unwrap().chain_new_head(&mut sync_io); + } _ => {/* Ignore other messages */}, } } diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 37ee862b5..8c8f669a2 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -24,7 +24,7 @@ use io::SyncIo; use chain::ChainSync; use ::SyncConfig; use ethcore::receipt::Receipt; -use ethcore::transaction::{LocalizedTransaction, Transaction, Action}; +use ethcore::transaction::{LocalizedTransaction, SignedTransaction, Transaction, Action}; use ethcore::filter::Filter; use ethcore::log_entry::LocalizedLogEntry; @@ -311,7 +311,7 @@ impl BlockChainClient for TestBlockChainClient { } } - fn prepare_sealing(&self, author: Address, extra_data: Bytes) -> Option { + fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option { unimplemented!() } From 9d664336b5e2bdd99855ca9961cc2da0ab4b9b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 13:28:37 +0100 Subject: [PATCH 441/753] Tratifying Miner --- miner/src/lib.rs | 4 +- miner/src/miner.rs | 90 ++++++++++++++++++++++++--------------- parity/main.rs | 2 +- rpc/src/v1/impls/eth.rs | 2 +- sync/src/chain.rs | 4 +- sync/src/tests/helpers.rs | 4 +- 6 files changed, 65 insertions(+), 41 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index ae6235393..36b040b78 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -31,7 +31,8 @@ mod transaction_queue; use std::ops::*; use std::sync::*; -pub use miner::Miner; +pub use miner::{Miner, MinerService}; + pub struct EthMiner { miner: Miner, @@ -45,6 +46,7 @@ impl EthMiner { }) } } + impl Deref for EthMiner { type Target = Miner; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 501f8c35c..64d3c9083 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -17,16 +17,45 @@ use util::*; use std::sync::atomic::AtomicBool; use rayon::prelude::*; -use ethcore::views::{HeaderView, BlockView}; -use ethcore::header::{BlockNumber, Header as BlockHeader}; -use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo}; +use ethcore::views::{BlockView}; +use ethcore::client::{BlockChainClient, BlockId}; use ethcore::block::*; use ethcore::error::*; use ethcore::transaction::SignedTransaction; -use transaction_queue::{TransactionQueue, TransactionQueueStatus}; +use transaction_queue::{TransactionQueue}; + +pub trait MinerService { + fn status(&self) -> MinerStatus; + + fn import_transactions(&self, transactions: Vec, fetch_nonce: T) + where T: Fn(&Address) -> U256; + + /// called when blocks are imported to chain, updates transactions queue + fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]); + + /// Set the author that we will seal blocks as. + fn set_author(&self, author: Address); + + /// Set the extra_data that we will seal blocks with. + fn set_extra_data(&self, extra_data: Bytes); + + /// New chain head event. Restart mining operation. + fn prepare_sealing(&self, chain: &BlockChainClient); + + /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. + fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex>; + + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; +} + +pub struct MinerStatus { + pub transaction_queue_pending: usize, + pub transaction_queue_future: usize, +} pub struct Miner { - /// Transactions Queue transaction_queue: Mutex, // for sealing... @@ -36,12 +65,8 @@ pub struct Miner { extra_data: RwLock, } -pub struct MinerStatus { - pub transaction_queue_pending: usize, - pub transaction_queue_future: usize, -} - impl Miner { + /// Creates new instance of miner pub fn new() -> Miner { Miner { transaction_queue: Mutex::new(TransactionQueue::new()), @@ -52,7 +77,20 @@ impl Miner { } } - pub fn status(&self) -> MinerStatus { + /// Get the author that we will seal blocks as. + fn author(&self) -> Address { + *self.author.read().unwrap() + } + + /// Get the extra_data that we will seal blocks wuth. + fn extra_data(&self) -> Bytes { + self.extra_data.read().unwrap().clone() + } +} + +impl MinerService for Miner { + + fn status(&self) -> MinerStatus { let status = self.transaction_queue.lock().unwrap().status(); MinerStatus { transaction_queue_pending: status.pending, @@ -60,34 +98,22 @@ impl Miner { } } - pub fn import_transactions(&self, transactions: Vec, fetch_nonce: T) + fn import_transactions(&self, transactions: Vec, fetch_nonce: T) where T: Fn(&Address) -> U256 { let mut transaction_queue = self.transaction_queue.lock().unwrap(); transaction_queue.add_all(transactions, fetch_nonce); } - /// Get the author that we will seal blocks as. - pub fn author(&self) -> Address { - *self.author.read().unwrap() - } - - /// Set the author that we will seal blocks as. - pub fn set_author(&self, author: Address) { + fn set_author(&self, author: Address) { *self.author.write().unwrap() = author; } - /// Get the extra_data that we will seal blocks wuth. - pub fn extra_data(&self) -> Bytes { - self.extra_data.read().unwrap().clone() - } - /// Set the extra_data that we will seal blocks with. - pub fn set_extra_data(&self, extra_data: Bytes) { + fn set_extra_data(&self, extra_data: Bytes) { *self.extra_data.write().unwrap() = extra_data; } - /// New chain head event. Restart mining operation. - pub fn prepare_sealing(&self, chain: &BlockChainClient) { + fn prepare_sealing(&self, chain: &BlockChainClient) { let no_of_transactions = 128; let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); @@ -99,8 +125,7 @@ impl Miner { *self.sealing_block.lock().unwrap() = b; } - /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - pub fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { + fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { if self.sealing_block.lock().unwrap().is_none() { self.sealing_enabled.store(true, atomic::Ordering::Relaxed); // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. @@ -109,9 +134,7 @@ impl Miner { &self.sealing_block } - /// Submit `seal` as a valid solution for the header of `pow_hash`. - /// Will check the seal, but not actually insert the block into the chain. - pub fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { + fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { let mut maybe_b = self.sealing_block.lock().unwrap(); match *maybe_b { Some(ref b) if b.hash() == pow_hash => {} @@ -132,8 +155,7 @@ impl Miner { } } - /// called when block is imported to chain, updates transactions queue and propagates the blocks - pub fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]) { + fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]) { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockId::Hash(hash.clone())) diff --git a/parity/main.rs b/parity/main.rs index a0bc87a03..89668a456 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -50,7 +50,7 @@ use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethsync::{EthSync, SyncConfig}; -use ethminer::{EthMiner}; +use ethminer::{EthMiner, MinerService}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 46d875c99..d40761b09 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::sync::{Arc, Weak, Mutex, RwLock}; use std::ops::Deref; use ethsync::{EthSync, SyncState}; -use ethminer::{EthMiner}; +use ethminer::{EthMiner, MinerService}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 2669b71e2..cb584f51d 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -38,7 +38,7 @@ use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::transaction::SignedTransaction; use ethcore::block::Block; -use ethminer::EthMiner; +use ethminer::{EthMiner, MinerService}; use io::SyncIo; use time; use super::SyncConfig; @@ -1285,7 +1285,7 @@ mod tests { use super::{PeerInfo, PeerAsking}; use ethcore::header::*; use ethcore::client::*; - use ethminer::EthMiner; + use ethminer::{EthMiner, MinerService}; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 8c8f669a2..9a4dd2814 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -311,11 +311,11 @@ impl BlockChainClient for TestBlockChainClient { } } - fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option { + fn prepare_sealing(&self, _author: Address, _extra_data: Bytes, _transactions: Vec) -> Option { unimplemented!() } - fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result { + fn try_seal(&self, _block: ClosedBlock, _seal: Vec) -> Result { unimplemented!() } } From 6ad0ba8fe24bf35c9a74b48a25c6e84dc132429f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 9 Mar 2016 17:11:15 +0400 Subject: [PATCH 442/753] basic commands --- Cargo.lock | 20 ++++++++++++++++++++ Cargo.toml | 1 + parity/main.rs | 34 ++++++++++++++++++++++++++++++++++ util/src/keys/store.rs | 1 + 4 files changed, 56 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 55ed996ed..65ca8f566 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -680,6 +681,17 @@ dependencies = [ "librocksdb-sys 0.2.1 (git+https://github.com/arkpar/rust-rocksdb.git)", ] +[[package]] +name = "rpassword" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rust-crypto" version = "0.2.34" @@ -813,6 +825,14 @@ dependencies = [ "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termios" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.34" diff --git a/Cargo.toml b/Cargo.toml index 9b8ec6405..0852a16bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ fdlimit = { path = "util/fdlimit" } daemonize = "0.2" ethcore-devtools = { path = "devtools" } number_prefix = "0.2" +rpassword = "0.1" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index 296e1df65..a442f4fdb 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -32,6 +32,7 @@ extern crate fdlimit; extern crate daemonize; extern crate time; extern crate number_prefix; +extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -70,6 +71,7 @@ Parity. Ethereum Client. Usage: parity daemon [options] [ --no-bootstrap | ... ] + parity account parity [options] [ --no-bootstrap | ... ] Protocol Options: @@ -126,8 +128,10 @@ Miscellaneous Options: #[derive(Debug, RustcDecodable)] struct Args { cmd_daemon: bool, + cmd_account: bool, arg_pid_file: String, arg_enode: Vec, + arg_command: String, flag_chain: String, flag_testnet: bool, flag_datadir: String, @@ -337,9 +341,39 @@ impl Configuration { .start() .unwrap_or_else(|e| die!("Couldn't daemonize; {}", e)); } + if self.args.cmd_account { + self.execute_account_cli(&self.args.arg_command); + return; + } self.execute_client(); } + fn execute_account_cli(&self, command: &str) { + use util::keys::store::SecretStore; + use rpassword::read_password; + let mut secret_store = SecretStore::new(); + if command == "new" { + println!("Please note that password is NOT RECOVERABLE."); + println!("Type password: "); + let password = read_password().unwrap(); + println!("Repeat password: "); + let password_repeat = read_password().unwrap(); + if password != password_repeat { + println!("Passwords do not match!"); + return; + } + println!("New account address:"); + let new_address = secret_store.new_account(&password).unwrap(); + println!("{:?}", new_address); + } + if command == "list" { + println!("Known addresses:"); + for &(addr, _) in secret_store.accounts().unwrap().iter() { + println!("{:?}", addr); + } + } + } + fn execute_client(&self) { // Setup logging setup_log(&self.args.flag_logging); diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 625d6fd8f..dcc165259 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -84,6 +84,7 @@ impl SecretStore { let mut path = ::std::env::home_dir().expect("Failed to get home dir"); path.push(".parity"); path.push("keys"); + ::std::fs::create_dir_all(&path).expect("Should panic since it is critical to be able to access home dir"); Self::new_in(&path) } From 363de973c90ed916959e8bf912f8ebde7f3aafa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 14:26:28 +0100 Subject: [PATCH 443/753] Adding documentation and ditching EthMiner --- miner/src/lib.rs | 54 ++++++++++++++++++++++----------------- miner/src/miner.rs | 34 +++++++++++++++++++----- parity/main.rs | 6 ++--- rpc/src/v1/impls/eth.rs | 6 ++--- sync/src/chain.rs | 10 ++++---- sync/src/lib.rs | 4 +-- sync/src/tests/helpers.rs | 4 +-- 7 files changed, 74 insertions(+), 44 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 36b040b78..591b73402 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -18,6 +18,37 @@ #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] +//! Miner module +//! Keeps track of transactions and mined block. +//! +//! Usage example: +//! +//! ```rust +//! extern crate ethcore_util as util; +//! extern crate ethcore; +//! extern crate ethminer; +//! use std::env; +//! use std::sync::Arc; +//! use util::network::{NetworkService, NetworkConfiguration}; +//! use ethcore::client::{Client, ClientConfig}; +//! use ethcore::ethereum; +//! use ethminer::{Miner, MinerService}; +//! +//! fn main() { +//! let dir = env::temp_dir(); +//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); +//! +//! let miner: Miner = Miner::default(); +//! // get status +//! assert_eq!(miner.status().transaction_queue_pending, 0); +//! +//! // Check block for sealing +//! miner.prepare_sealing(&client); +//! assert_eq!(miner.sealing_block(&client).lock().unwrap().is_some()); +//! } +//! ``` + + #[macro_use] extern crate log; #[macro_use] @@ -29,28 +60,5 @@ extern crate rayon; mod miner; mod transaction_queue; -use std::ops::*; -use std::sync::*; pub use miner::{Miner, MinerService}; - -pub struct EthMiner { - miner: Miner, -} - -impl EthMiner { - /// Creates and register protocol with the network service - pub fn new() -> Arc { - Arc::new(EthMiner { - miner: Miner::new(), - }) - } -} - -impl Deref for EthMiner { - type Target = Miner; - - fn deref(&self) -> &Self::Target { - &self.miner - } -} diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 64d3c9083..f5ad32d2d 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -24,21 +24,28 @@ use ethcore::error::*; use ethcore::transaction::SignedTransaction; use transaction_queue::{TransactionQueue}; +/// Miner external API pub trait MinerService { + + /// Returns miner's status. fn status(&self) -> MinerStatus; + /// Imports transactions to transaction queue. fn import_transactions(&self, transactions: Vec, fetch_nonce: T) where T: Fn(&Address) -> U256; - /// called when blocks are imported to chain, updates transactions queue - fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]); - /// Set the author that we will seal blocks as. fn set_author(&self, author: Address); /// Set the extra_data that we will seal blocks with. fn set_extra_data(&self, extra_data: Bytes); + /// Removes all transactions from the queue and restart mining operation. + fn clear_and_reset(&self, chain: &BlockChainClient); + + /// called when blocks are imported to chain, updates transactions queue. + fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]); + /// New chain head event. Restart mining operation. fn prepare_sealing(&self, chain: &BlockChainClient); @@ -50,11 +57,15 @@ pub trait MinerService { fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; } +/// Mining status pub struct MinerStatus { + /// Number of transactions in queue with state `pending` (ready to be included in block) pub transaction_queue_pending: usize, + /// Number of transactions in queue with state `future` (not yet ready to be included in block) pub transaction_queue_future: usize, } +/// Keeps track of transactions using priority queue and holds currently mined block. pub struct Miner { transaction_queue: Mutex, @@ -65,9 +76,8 @@ pub struct Miner { extra_data: RwLock, } -impl Miner { - /// Creates new instance of miner - pub fn new() -> Miner { +impl Default for Miner { + fn default() -> Miner { Miner { transaction_queue: Mutex::new(TransactionQueue::new()), sealing_enabled: AtomicBool::new(false), @@ -76,6 +86,13 @@ impl Miner { extra_data: RwLock::new(Vec::new()), } } +} + +impl Miner { + /// Creates new instance of miner + pub fn new() -> Arc { + Arc::new(Miner::default()) + } /// Get the author that we will seal blocks as. fn author(&self) -> Address { @@ -90,6 +107,11 @@ impl Miner { impl MinerService for Miner { + fn clear_and_reset(&self, chain: &BlockChainClient) { + self.transaction_queue.lock().unwrap().clear(); + self.prepare_sealing(chain); + } + fn status(&self) -> MinerStatus { let status = self.transaction_queue.lock().unwrap().status(); MinerStatus { diff --git a/parity/main.rs b/parity/main.rs index 89668a456..d75bdcb57 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -50,7 +50,7 @@ use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethsync::{EthSync, SyncConfig}; -use ethminer::{EthMiner, MinerService}; +use ethminer::{Miner, MinerService}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; @@ -192,7 +192,7 @@ fn setup_log(init: &Option) { } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, miner: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) { +fn setup_rpc_server(client: Arc, sync: Arc, miner: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) { use rpc::v1::*; let mut server = rpc::HttpServer::new(1); @@ -382,7 +382,7 @@ impl Configuration { let client = service.client(); // Miner - let miner = EthMiner::new(); + let miner = Miner::new(); miner.set_author(self.author()); miner.set_extra_data(self.extra_data()); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d40761b09..a9ee389f8 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::sync::{Arc, Weak, Mutex, RwLock}; use std::ops::Deref; use ethsync::{EthSync, SyncState}; -use ethminer::{EthMiner, MinerService}; +use ethminer::{Miner, MinerService}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; @@ -38,13 +38,13 @@ use v1::helpers::{PollFilter, PollManager}; pub struct EthClient { client: Weak, sync: Weak, - miner: Weak, + miner: Weak, hashrates: RwLock>, } impl EthClient { /// Creates new EthClient. - pub fn new(client: &Arc, sync: &Arc, miner: &Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc, miner: &Arc) -> Self { EthClient { client: Arc::downgrade(client), sync: Arc::downgrade(sync), diff --git a/sync/src/chain.rs b/sync/src/chain.rs index cb584f51d..4c7b0893a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -38,7 +38,7 @@ use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::transaction::SignedTransaction; use ethcore::block::Block; -use ethminer::{EthMiner, MinerService}; +use ethminer::{Miner, MinerService}; use io::SyncIo; use time; use super::SyncConfig; @@ -212,14 +212,14 @@ pub struct ChainSync { /// Network ID network_id: U256, /// Miner - miner: Arc, + miner: Arc, } type RlpResponseResult = Result, PacketDecodeError>; impl ChainSync { /// Create a new instance of syncing strategy. - pub fn new(config: SyncConfig, miner: Arc) -> ChainSync { + pub fn new(config: SyncConfig, miner: Arc) -> ChainSync { ChainSync { state: SyncState::NotSynced, starting_block: 0, @@ -1285,7 +1285,7 @@ mod tests { use super::{PeerInfo, PeerAsking}; use ethcore::header::*; use ethcore::client::*; - use ethminer::{EthMiner, MinerService}; + use ethminer::{Miner, MinerService}; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); @@ -1395,7 +1395,7 @@ mod tests { } fn dummy_sync_with_peer(peer_latest_hash: H256) -> ChainSync { - let mut sync = ChainSync::new(SyncConfig::default(), EthMiner::new()); + let mut sync = ChainSync::new(SyncConfig::default(), Miner::new()); sync.peers.insert(0, PeerInfo { protocol_version: 0, diff --git a/sync/src/lib.rs b/sync/src/lib.rs index be01d2b7b..dd331b5da 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -65,7 +65,7 @@ use util::TimerToken; use util::{U256, ONE_U256}; use ethcore::client::Client; use ethcore::service::SyncMessage; -use ethminer::EthMiner; +use ethminer::Miner; use io::NetSyncIo; use chain::ChainSync; @@ -105,7 +105,7 @@ pub use self::chain::{SyncStatus, SyncState}; impl EthSync { /// Creates and register protocol with the network service - pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc, miner: Arc) -> Arc { + pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc, miner: Arc) -> Arc { let sync = Arc::new(EthSync { chain: chain, sync: RwLock::new(ChainSync::new(config, miner)), diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 9a4dd2814..52a1feba4 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -19,7 +19,7 @@ use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, use ethcore::header::{Header as BlockHeader, BlockNumber}; use ethcore::block::*; use ethcore::error::*; -use ethminer::EthMiner; +use ethminer::Miner; use io::SyncIo; use chain::ChainSync; use ::SyncConfig; @@ -392,7 +392,7 @@ impl TestNet { for _ in 0..n { net.peers.push(TestPeer { chain: TestBlockChainClient::new(), - sync: ChainSync::new(SyncConfig::default(), EthMiner::new()), + sync: ChainSync::new(SyncConfig::default(), Miner::new()), queue: VecDeque::new(), }); } From 493c61f09d9a2e8b12579c8a27cdc9ef22766651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 15:22:06 +0100 Subject: [PATCH 444/753] Minimal gas price threshold. Closes: #636 --- miner/src/miner.rs | 32 ++++++++++++++++---------------- miner/src/transaction_queue.rs | 34 ++++++++++++++++++++++++++++++++++ parity/main.rs | 8 ++++++++ 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index f5ad32d2d..2c18f3a79 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -24,7 +24,7 @@ use ethcore::error::*; use ethcore::transaction::SignedTransaction; use transaction_queue::{TransactionQueue}; -/// Miner external API +/// Miner client API pub trait MinerService { /// Returns miner's status. @@ -34,12 +34,6 @@ pub trait MinerService { fn import_transactions(&self, transactions: Vec, fetch_nonce: T) where T: Fn(&Address) -> U256; - /// Set the author that we will seal blocks as. - fn set_author(&self, author: Address); - - /// Set the extra_data that we will seal blocks with. - fn set_extra_data(&self, extra_data: Bytes); - /// Removes all transactions from the queue and restart mining operation. fn clear_and_reset(&self, chain: &BlockChainClient); @@ -103,6 +97,21 @@ impl Miner { fn extra_data(&self) -> Bytes { self.extra_data.read().unwrap().clone() } + + /// Set the author that we will seal blocks as. + pub fn set_author(&self, author: Address) { + *self.author.write().unwrap() = author; + } + + /// Set the extra_data that we will seal blocks with. + pub fn set_extra_data(&self, extra_data: Bytes) { + *self.extra_data.write().unwrap() = extra_data; + } + + /// Set minimal gas price of transaction to be accepted for mining. + pub fn set_minimal_gas_price(&self, min_gas_price: U256) { + self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price); + } } impl MinerService for Miner { @@ -126,15 +135,6 @@ impl MinerService for Miner { transaction_queue.add_all(transactions, fetch_nonce); } - fn set_author(&self, author: Address) { - *self.author.write().unwrap() = author; - } - - - fn set_extra_data(&self, extra_data: Bytes) { - *self.extra_data.write().unwrap() = extra_data; - } - fn prepare_sealing(&self, chain: &BlockChainClient) { let no_of_transactions = 128; let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 3e0d931b5..ed8cf801e 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -159,6 +159,8 @@ pub struct TransactionQueueStatus { /// TransactionQueue implementation pub struct TransactionQueue { + /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) + minimal_gas_price: U256, /// Priority queue for transactions that can go to block current: TransactionSet, /// Priority queue for transactions that has been received but are not yet valid to go to block @@ -189,6 +191,7 @@ impl TransactionQueue { }; TransactionQueue { + minimal_gas_price: U256::zero(), current: current, future: future, by_hash: HashMap::new(), @@ -196,6 +199,12 @@ impl TransactionQueue { } } + /// Sets new gas price threshold for incoming transactions. + /// Any transactions already imported to the queue are not affected. + pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) { + self.minimal_gas_price = min_gas_price; + } + /// Returns current status for this queue pub fn status(&self) -> TransactionQueueStatus { TransactionQueueStatus { @@ -215,6 +224,15 @@ impl TransactionQueue { /// Add signed transaction to queue to be verified and imported pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) where T: Fn(&Address) -> U256 { + + if tx.gas_price < self.minimal_gas_price { + trace!(target: "sync", + "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", + tx.hash(), tx.gas_price, self.minimal_gas_price + ); + return; + } + // Everything ok - import transaction self.import_tx(VerifiedTransaction::new(tx), fetch_nonce); } @@ -503,6 +521,22 @@ mod test { assert_eq!(stats.pending, 1); } + #[test] + fn should_not_import_transaction_below_min_gas_price_threshold() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + txq.set_minimal_gas_price(tx.gas_price + U256::one()); + + // when + txq.add(tx, &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + #[test] fn should_import_txs_from_same_sender() { // given diff --git a/parity/main.rs b/parity/main.rs index d75bdcb57..b3a0224d8 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -108,6 +108,7 @@ API and Console Options: --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). Sealing/Mining Options: + --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 50000000000]. --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. @@ -161,6 +162,7 @@ struct Args { flag_rpcapi: Option, flag_logging: Option, flag_version: bool, + flag_gasprice: String, flag_author: String, flag_extra_data: Option, } @@ -248,6 +250,11 @@ impl Configuration { Address::from_str(&self.args.flag_author).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) } + fn gasprice(&self) -> U256 { + U256::from_dec_str(self.args.flag_gasprice).unwrap_or_else(|_| die("{}: Invalid gasprice given. Must be a + decimal unsigned 256-bit number.")) + } + fn extra_data(&self) -> Bytes { match self.args.flag_extra_data { Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(), @@ -385,6 +392,7 @@ impl Configuration { let miner = Miner::new(); miner.set_author(self.author()); miner.set_extra_data(self.extra_data()); + miner.set_minimal_gas_price(self.gasprice()); // Sync let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); From 3d74e5bd473d466d20b7169ee56f0316ea72d2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 15:27:07 +0100 Subject: [PATCH 445/753] Fixing doctest --- miner/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 591b73402..4fccc6d51 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -27,14 +27,16 @@ //! extern crate ethcore_util as util; //! extern crate ethcore; //! extern crate ethminer; +//! use std::ops::Deref; //! use std::env; //! use std::sync::Arc; //! use util::network::{NetworkService, NetworkConfiguration}; -//! use ethcore::client::{Client, ClientConfig}; +//! use ethcore::client::{Client, ClientConfig, BlockChainClient}; //! use ethcore::ethereum; //! use ethminer::{Miner, MinerService}; //! //! fn main() { +//! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let dir = env::temp_dir(); //! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); //! @@ -43,8 +45,8 @@ //! assert_eq!(miner.status().transaction_queue_pending, 0); //! //! // Check block for sealing -//! miner.prepare_sealing(&client); -//! assert_eq!(miner.sealing_block(&client).lock().unwrap().is_some()); +//! miner.prepare_sealing(client.deref()); +//! assert!(miner.sealing_block(client.deref()).lock().unwrap().is_some()); //! } //! ``` From bcb9b0e45723f6e35035505ad89f8f747909041b Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 9 Mar 2016 15:32:27 +0100 Subject: [PATCH 446/753] wait_for_exit takes only one input param, which is PanicHandler --- parity/main.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 296e1df65..adc3972e4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -43,7 +43,7 @@ use std::path::PathBuf; use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; -use util::panics::{MayPanic, PanicHandler}; +use util::panics::{MayPanic, ForwardPanic, PanicHandler}; use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; @@ -341,6 +341,9 @@ impl Configuration { } fn execute_client(&self) { + // Setup panic handler + let panic_handler = PanicHandler::new_in_arc(); + // Setup logging setup_log(&self.args.flag_logging); // Raise fdlimit @@ -367,6 +370,7 @@ impl Configuration { client_config.name = self.args.flag_identity.clone(); client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); + panic_handler.forward_from(&service); let client = service.client().clone(); client.set_author(self.author()); client.set_extra_data(self.extra_data()); @@ -375,7 +379,7 @@ impl Configuration { let sync = EthSync::register(service.network(), sync_config, client); // Setup rpc - let server_handler = if self.args.flag_jsonrpc || self.args.flag_rpc { + if self.args.flag_jsonrpc || self.args.flag_rpc { let url = format!("{}:{}", self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_addr), self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) @@ -384,10 +388,12 @@ impl Configuration { let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect()) - } else { - None - }; + let server_handler = setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect()); + if let Some(handler) = server_handler { + panic_handler.forward_from(handler.deref()); + } + + } // Register IO handler let io_handler = Arc::new(ClientIoHandler { @@ -398,23 +404,20 @@ impl Configuration { service.io().register_handler(io_handler).expect("Error registering IO handler"); // Handle exit - wait_for_exit(&service, server_handler); + wait_for_exit(panic_handler); } } -fn wait_for_exit(client_service: &ClientService, server_handler: Option>) { +fn wait_for_exit(panic_handler: Arc) { let exit = Arc::new(Condvar::new()); // Handle possible exits let e = exit.clone(); CtrlC::set_handler(move || { e.notify_all(); }); - let e = exit.clone(); - client_service.on_panic(move |_reason| { e.notify_all(); }); - if let Some(handler) = server_handler { - let e = exit.clone(); - handler.on_panic(move |_reason| { e.notify_all(); }); - } + // Handle panics + let e = exit.clone(); + panic_handler.on_panic(move |_reason| { e.notify_all(); }); // Wait for signal let mutex = Mutex::new(()); From 7ff4d145448487685be000f572f790c3bcef5ae9 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 9 Mar 2016 19:27:44 +0400 Subject: [PATCH 447/753] adding return to if branch --- parity/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/parity/main.rs b/parity/main.rs index 1a2847439..9a45980ef 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -365,6 +365,7 @@ impl Configuration { println!("New account address:"); let new_address = secret_store.new_account(&password).unwrap(); println!("{:?}", new_address); + return; } if command == "list" { println!("Known addresses:"); From 082a4d9078cff6b90f4b01ca3614cc9c3825f265 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 9 Mar 2016 17:31:43 +0100 Subject: [PATCH 448/753] jsonrpc uses client and sync interfaces as a preparetion for jsonrpc tests --- ethcore/src/client.rs | 73 +++++++++++++++++++++------------------ parity/main.rs | 2 +- rpc/src/v1/impls/eth.rs | 25 +++++++------- rpc/src/v1/impls/net.rs | 12 +++---- sync/src/lib.rs | 18 +++++++--- sync/src/tests/helpers.rs | 9 +++++ 6 files changed, 81 insertions(+), 58 deletions(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 8471666aa..374011f71 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -182,6 +182,13 @@ pub trait BlockChainClient : Sync + Send { /// Returns logs matching given filter. fn logs(&self, filter: Filter) -> Vec; + + /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. + fn sealing_block(&self) -> &Mutex>; + + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error>; } #[derive(Default, Clone, Debug, Eq, PartialEq)] @@ -511,39 +518,6 @@ impl Client where V: Verifier { trace!("Sealing: number={}, hash={}, diff={}", b.hash(), b.block().header().difficulty(), b.block().header().number()); *self.sealing_block.lock().unwrap() = Some(b); } - - /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - pub fn sealing_block(&self) -> &Mutex> { - if self.sealing_block.lock().unwrap().is_none() { - self.sealing_enabled.store(true, atomic::Ordering::Relaxed); - // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. - self.prepare_sealing(); - } - &self.sealing_block - } - - /// Submit `seal` as a valid solution for the header of `pow_hash`. - /// Will check the seal, but not actually insert the block into the chain. - pub fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { - let mut maybe_b = self.sealing_block.lock().unwrap(); - match *maybe_b { - Some(ref b) if b.hash() == pow_hash => {} - _ => { return Err(Error::PowHashInvalid); } - } - - let b = maybe_b.take(); - match b.unwrap().try_seal(self.engine.deref().deref(), seal) { - Err(old) => { - *maybe_b = Some(old); - Err(Error::PowInvalid) - } - Ok(sealed) => { - // TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice. - try!(self.import_block(sealed.rlp_bytes())); - Ok(()) - } - } - } } // TODO: need MinerService MinerIoHandler @@ -702,6 +676,39 @@ impl BlockChainClient for Client where V: Verifier { }) .collect() } + + /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. + fn sealing_block(&self) -> &Mutex> { + if self.sealing_block.lock().unwrap().is_none() { + self.sealing_enabled.store(true, atomic::Ordering::Relaxed); + // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. + self.prepare_sealing(); + } + &self.sealing_block + } + + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + fn submit_seal(&self, pow_hash: H256, seal: Vec) -> Result<(), Error> { + let mut maybe_b = self.sealing_block.lock().unwrap(); + match *maybe_b { + Some(ref b) if b.hash() == pow_hash => {} + _ => { return Err(Error::PowHashInvalid); } + } + + let b = maybe_b.take(); + match b.unwrap().try_seal(self.engine.deref().deref(), seal) { + Err(old) => { + *maybe_b = Some(old); + Err(Error::PowInvalid) + } + Ok(sealed) => { + // TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice. + try!(self.import_block(sealed.rlp_bytes())); + Ok(()) + } + } + } } impl MayPanic for Client { diff --git a/parity/main.rs b/parity/main.rs index ceb58e31e..1cd2970b4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -48,7 +48,7 @@ use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; -use ethsync::{EthSync, SyncConfig}; +use ethsync::{EthSync, SyncConfig, SyncStatusProvider}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 7113c55b1..abcb54ab7 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -17,7 +17,7 @@ //! Eth rpc implementation. use std::collections::HashMap; use std::sync::{Arc, Weak, Mutex, RwLock}; -use ethsync::{EthSync, SyncState}; +use ethsync::{SyncStatusProvider, SyncState}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; @@ -25,7 +25,6 @@ use util::rlp::encode; use ethcore::client::*; use ethcore::block::{IsBlock}; use ethcore::views::*; -//#[macro_use] extern crate log; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; @@ -33,15 +32,15 @@ use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncIn use v1::helpers::{PollFilter, PollManager}; /// Eth rpc implementation. -pub struct EthClient { - client: Weak, - sync: Weak, +pub struct EthClient where C: BlockChainClient, S: SyncStatusProvider { + client: Weak, + sync: Weak, hashrates: RwLock>, } -impl EthClient { +impl EthClient where C: BlockChainClient, S: SyncStatusProvider { /// Creates new EthClient. - pub fn new(client: &Arc, sync: &Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc) -> Self { EthClient { client: Arc::downgrade(client), sync: Arc::downgrade(sync), @@ -95,7 +94,7 @@ impl EthClient { } } -impl Eth for EthClient { +impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncStatusProvider + 'static { fn protocol_version(&self, params: Params) -> Result { match params { Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)), @@ -256,14 +255,14 @@ impl Eth for EthClient { } /// Eth filter rpc implementation. -pub struct EthFilterClient { - client: Weak, +pub struct EthFilterClient where C: BlockChainClient { + client: Weak, polls: Mutex>, } -impl EthFilterClient { +impl EthFilterClient where C: BlockChainClient { /// Creates new Eth filter client. - pub fn new(client: &Arc) -> Self { + pub fn new(client: &Arc) -> Self { EthFilterClient { client: Arc::downgrade(client), polls: Mutex::new(PollManager::new()) @@ -271,7 +270,7 @@ impl EthFilterClient { } } -impl EthFilter for EthFilterClient { +impl EthFilter for EthFilterClient where C: BlockChainClient + 'static { fn new_filter(&self, params: Params) -> Result { from_params::<(Filter,)>(params) .and_then(|(filter,)| { diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 9e24caad2..a686ed66f 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -17,24 +17,24 @@ //! Net rpc implementation. use std::sync::{Arc, Weak}; use jsonrpc_core::*; -use ethsync::EthSync; +use ethsync::SyncStatusProvider; use v1::traits::Net; /// Net rpc implementation. -pub struct NetClient { - sync: Weak +pub struct NetClient where S: SyncStatusProvider { + sync: Weak } -impl NetClient { +impl NetClient where S: SyncStatusProvider { /// Creates new NetClient. - pub fn new(sync: &Arc) -> Self { + pub fn new(sync: &Arc) -> Self { NetClient { sync: Arc::downgrade(sync) } } } -impl Net for NetClient { +impl Net for NetClient where S: SyncStatusProvider + 'static { fn version(&self, _: Params) -> Result { Ok(Value::U64(take_weak!(self.sync).status().protocol_version as u64)) } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 74541660d..427a58e15 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -93,6 +93,12 @@ impl Default for SyncConfig { } } +/// Current sync status +pub trait SyncStatusProvider: Send + Sync { + /// Get sync status + fn status(&self) -> SyncStatus; +} + /// Ethereum network protocol handler pub struct EthSync { /// Shared blockchain client. TODO: this should evetually become an IPC endpoint @@ -114,11 +120,6 @@ impl EthSync { sync } - /// Get sync status - pub fn status(&self) -> SyncStatus { - self.sync.read().unwrap().status() - } - /// Stop sync pub fn stop(&mut self, io: &mut NetworkContext) { self.sync.write().unwrap().abort(&mut NetSyncIo::new(io, self.chain.deref())); @@ -130,6 +131,13 @@ impl EthSync { } } +impl SyncStatusProvider for EthSync { + /// Get sync status + fn status(&self) -> SyncStatus { + self.sync.read().unwrap().status() + } +} + impl NetworkProtocolHandler for EthSync { fn initialize(&self, io: &NetworkContext) { io.register_timer(0, 1000).expect("Error registering sync timer"); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index e170a4a85..e7d5cf57f 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -25,6 +25,7 @@ use ethcore::receipt::Receipt; use ethcore::transaction::LocalizedTransaction; use ethcore::filter::Filter; use ethcore::log_entry::LocalizedLogEntry; +use ethcore::block::ClosedBlock; pub struct TestBlockChainClient { pub blocks: RwLock>, @@ -125,6 +126,14 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn sealing_block(&self) -> &Mutex> { + unimplemented!(); + } + + fn submit_seal(&self, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { + unimplemented!(); + } + fn block_header(&self, id: BlockId) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) } From 423dd7e0a967a808b769304a245f4316e5a2aa5b Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 9 Mar 2016 18:04:13 +0100 Subject: [PATCH 449/753] updated jsonrpc-core and http-server libs --- Cargo.lock | 10 +++++----- parity/main.rs | 4 ++-- rpc/Cargo.toml | 4 ++-- rpc/src/lib.rs | 22 ++++++++++------------ 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55ed996ed..15845c806 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,8 +228,8 @@ dependencies = [ "ethcore 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", - "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -400,7 +400,7 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "1.2.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -411,11 +411,11 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" -version = "2.1.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/parity/main.rs b/parity/main.rs index adc3972e4..f28ef84c3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -193,7 +193,7 @@ fn setup_log(init: &Option) { fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) -> Option> { use rpc::v1::*; - let mut server = rpc::HttpServer::new(1); + let server = rpc::RpcServer::new(); for api in apis.into_iter() { match api { "web3" => server.add_delegate(Web3Client::new().to_delegate()), @@ -207,7 +207,7 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_dom } } } - Some(server.start_async(url, cors_domain)) + Some(server.start_http(url, cors_domain, 1)) } #[cfg(not(feature = "rpc"))] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index bfdf8f2d3..f324aba10 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -12,8 +12,8 @@ build = "build.rs" log = "0.3" serde = "0.7.0" serde_json = "0.7.0" -jsonrpc-core = "1.2" -jsonrpc-http-server = "2.1" +jsonrpc-core = "2.0" +jsonrpc-http-server = "3.0" ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 97a3a5fe5..731ded8c4 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -37,35 +37,33 @@ use self::jsonrpc_core::{IoHandler, IoDelegate}; pub mod v1; /// Http server. -pub struct HttpServer { - handler: IoHandler, - threads: usize, +pub struct RpcServer { + handler: Arc, } -impl HttpServer { +impl RpcServer { /// Construct new http server object with given number of threads. - pub fn new(threads: usize) -> HttpServer { - HttpServer { - handler: IoHandler::new(), - threads: threads, + pub fn new() -> RpcServer { + RpcServer { + handler: Arc::new(IoHandler::new()), } } /// Add io delegate. - pub fn add_delegate(&mut self, delegate: IoDelegate) where D: Send + Sync + 'static { + pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { self.handler.add_delegate(delegate); } /// Start server asynchronously in new thread and returns panic handler. - pub fn start_async(self, addr: &str, cors_domain: &str) -> Arc { + pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Arc { let addr = addr.to_owned(); let cors_domain = cors_domain.to_owned(); let panic_handler = PanicHandler::new_in_arc(); let ph = panic_handler.clone(); - let server = jsonrpc_http_server::Server::new(self.handler, self.threads); + let server = jsonrpc_http_server::Server::new(self.handler.clone()); thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { ph.catch_panic(move || { - server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain)); + server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads); }).unwrap() }).expect("Error while creating jsonrpc http thread"); panic_handler From c302fa9a4ebae4710ad98933539fbb4b6998b6f4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 9 Mar 2016 18:37:44 +0100 Subject: [PATCH 450/753] Style --- util/src/journaldb.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 3309612c2..1d854924a 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -243,9 +243,10 @@ impl JournalDB { { if canon_id == journal.id { for h in &journal.insertions { - match journal_overlay.backing_overlay.raw(&h) { - Some(&(ref d, rc)) if rc > 0 => canon_insertions.push((h.clone(), d.clone())), //TODO: optimizie this to avoid data copy - _ => () + if let Some(&(ref d, rc)) = journal_overlay.backing_overlay.raw(h) { + if rc > 0 { + canon_insertions.push((h.clone(), d.clone())); //TODO: optimize this to avoid data copy + } } } canon_deletions = journal.deletions; @@ -352,7 +353,7 @@ impl HashDB for JournalDB { ret } - fn lookup(&self, key: &H256) -> Option<&[u8]> { + fn lookup(&self, key: &H256) -> Option<&[u8]> { let k = self.transaction_overlay.raw(key); match k { Some(&(ref d, rc)) if rc > 0 => Some(d), @@ -573,7 +574,6 @@ mod tests { fn reopen_remove() { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let bar = H256::random(); let foo = { let mut jdb = JournalDB::new(dir.to_str().unwrap()); From 8a83e27d6a8f2f298e6b0dc44a60f9190e8e6c2a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 9 Mar 2016 22:55:41 +0400 Subject: [PATCH 451/753] cfg-test for noop verifier --- ethcore/src/verification/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs index 260121989..fe1f406cc 100644 --- a/ethcore/src/verification/mod.rs +++ b/ethcore/src/verification/mod.rs @@ -17,9 +17,11 @@ pub mod verification; pub mod verifier; mod canon_verifier; +#[cfg(test)] mod noop_verifier; pub use self::verification::*; pub use self::verifier::Verifier; pub use self::canon_verifier::CanonVerifier; +#[cfg(test)] pub use self::noop_verifier::NoopVerifier; From accc1db43fc46e3bd2ab425c778dcfaa843bdec8 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 9 Mar 2016 23:39:36 +0400 Subject: [PATCH 452/753] chaning docopt config a bit --- parity/main.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 9a45980ef..92400728d 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -71,7 +71,7 @@ Parity. Ethereum Client. Usage: parity daemon [options] [ --no-bootstrap | ... ] - parity account + parity account (new | list) parity [options] [ --no-bootstrap | ... ] Protocol Options: @@ -129,9 +129,10 @@ Miscellaneous Options: struct Args { cmd_daemon: bool, cmd_account: bool, + cmd_new: bool, + cmd_list: bool, arg_pid_file: String, arg_enode: Vec, - arg_command: String, flag_chain: String, flag_testnet: bool, flag_datadir: String, @@ -342,17 +343,17 @@ impl Configuration { .unwrap_or_else(|e| die!("Couldn't daemonize; {}", e)); } if self.args.cmd_account { - self.execute_account_cli(&self.args.arg_command); + self.execute_account_cli(); return; } self.execute_client(); } - fn execute_account_cli(&self, command: &str) { + fn execute_account_cli(&self) { use util::keys::store::SecretStore; use rpassword::read_password; let mut secret_store = SecretStore::new(); - if command == "new" { + if self.args.cmd_new { println!("Please note that password is NOT RECOVERABLE."); println!("Type password: "); let password = read_password().unwrap(); @@ -367,7 +368,7 @@ impl Configuration { println!("{:?}", new_address); return; } - if command == "list" { + if self.args.cmd_list { println!("Known addresses:"); for &(addr, _) in secret_store.accounts().unwrap().iter() { println!("{:?}", addr); From 8b042ac875f0abe9968f70d76b44773cd64c4350 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 9 Mar 2016 21:55:23 +0100 Subject: [PATCH 453/753] blockchain import_route --- ethcore/src/blockchain/block_info.rs | 6 +- ethcore/src/blockchain/blockchain.rs | 55 +++++++++--- ethcore/src/blockchain/import_route.rs | 119 +++++++++++++++++++++++++ ethcore/src/blockchain/mod.rs | 2 + 4 files changed, 167 insertions(+), 15 deletions(-) create mode 100644 ethcore/src/blockchain/import_route.rs diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index ce639bfed..335bdbb4e 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -18,6 +18,7 @@ use util::numbers::{U256,H256}; use header::BlockNumber; /// Brief info about inserted block. +#[derive(Clone)] pub struct BlockInfo { /// Block hash. pub hash: H256, @@ -30,6 +31,7 @@ pub struct BlockInfo { } /// Describes location of newly inserted block. +#[derive(Clone)] pub enum BlockLocation { /// It's part of the canon chain. CanonChain, @@ -42,6 +44,8 @@ pub enum BlockLocation { /// Hash of the newest common ancestor with old canon chain. ancestor: H256, /// Hashes of the blocks between ancestor and this block. - route: Vec + route: Vec, + /// Hashes of the blocks which were invalidated. + old_route: Vec, } } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index e529f50af..e57f7208a 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -28,7 +28,7 @@ use blockchain::best_block::BestBlock; use blockchain::bloom_indexer::BloomIndexer; use blockchain::tree_route::TreeRoute; use blockchain::update::ExtrasUpdate; -use blockchain::CacheSize; +use blockchain::{CacheSize, ImportRoute}; const BLOOM_INDEX_SIZE: usize = 16; const BLOOM_LEVELS: u8 = 3; @@ -414,14 +414,14 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, bytes: &[u8], receipts: Vec) { + pub fn insert_block(&self, bytes: &[u8], receipts: Vec) -> ImportRoute { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); let hash = header.sha3(); if self.is_known(&hash) { - return; + return ImportRoute::none(); } // store block in db @@ -435,8 +435,10 @@ impl BlockChain { block_receipts: self.prepare_block_receipts_update(receipts, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), - info: info + info: info.clone(), }); + + ImportRoute::from(info) } /// Applies extras update. @@ -549,9 +551,14 @@ impl BlockChain { match route.blocks.len() { 0 => BlockLocation::CanonChain, - _ => BlockLocation::BranchBecomingCanonChain { - ancestor: route.ancestor, - route: route.blocks.into_iter().skip(route.index).collect() + _ => { + let old_route = route.blocks.iter().take(route.index).cloned().collect::>(); + + BlockLocation::BranchBecomingCanonChain { + ancestor: route.ancestor, + route: route.blocks.into_iter().skip(route.index).collect(), + old_route: old_route.into_iter().rev().collect(), + } } } } else { @@ -572,7 +579,7 @@ impl BlockChain { BlockLocation::CanonChain => { block_hashes.insert(number, info.hash.clone()); }, - BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => { + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route, .. } => { let ancestor_number = self.block_number(ancestor).unwrap(); let start_number = ancestor_number + 1; @@ -661,7 +668,7 @@ impl BlockChain { ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) .add_bloom(&header.log_bloom(), header.number() as usize) }, - BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => { + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route, .. } => { let ancestor_number = self.block_number(ancestor).unwrap(); let start_number = ancestor_number + 1; @@ -825,7 +832,7 @@ mod tests { use rustc_serialize::hex::FromHex; use util::hash::*; use util::sha3::Hashable; - use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; + use blockchain::{BlockProvider, BlockChain, BlockChainConfig, ImportRoute}; use tests::helpers::*; use devtools::*; use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer}; @@ -943,10 +950,30 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); - bc.insert_block(&b1, vec![]); - bc.insert_block(&b2, vec![]); - bc.insert_block(&b3a, vec![]); - bc.insert_block(&b3b, vec![]); + let ir1 = bc.insert_block(&b1, vec![]); + let ir2 = bc.insert_block(&b2, vec![]); + let ir3b = bc.insert_block(&b3b, vec![]); + let ir3a = bc.insert_block(&b3a, vec![]); + + assert_eq!(ir1, ImportRoute { + validated_blocks: vec![b1_hash], + invalidated_blocks: vec![], + }); + + assert_eq!(ir2, ImportRoute { + validated_blocks: vec![b2_hash], + invalidated_blocks: vec![], + }); + + assert_eq!(ir3b, ImportRoute { + validated_blocks: vec![b3b_hash], + invalidated_blocks: vec![], + }); + + assert_eq!(ir3a, ImportRoute { + validated_blocks: vec![b3a_hash], + invalidated_blocks: vec![b3b_hash], + }); assert_eq!(bc.best_block_hash(), best_block_hash); assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0); diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs new file mode 100644 index 000000000..10629f2cb --- /dev/null +++ b/ethcore/src/blockchain/import_route.rs @@ -0,0 +1,119 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Import route. + +use util::hash::H256; +use blockchain::block_info::{BlockInfo, BlockLocation}; + +/// Import route for newly inserted block. +#[derive(Debug, PartialEq)] +pub struct ImportRoute { + /// Blocks that were invalidated by new block. + pub invalidated_blocks: Vec, + /// Blocks that were validted by new block. + pub validated_blocks: Vec, +} + +impl ImportRoute { + pub fn none() -> Self { + ImportRoute { + invalidated_blocks: vec![], + validated_blocks: vec![], + } + } +} + +impl From for ImportRoute { + fn from(info: BlockInfo) -> ImportRoute { + match info.location { + BlockLocation::CanonChain => ImportRoute { + invalidated_blocks: vec![], + validated_blocks: vec![info.hash], + }, + BlockLocation::Branch => ImportRoute::none(), + BlockLocation::BranchBecomingCanonChain { mut route, old_route, .. } => { + route.push(info.hash); + ImportRoute { + invalidated_blocks: old_route, + validated_blocks: route, + } + } + } + } +} + +#[cfg(test)] +mod tests { + use util::hash::H256; + use util::numbers::U256; + use blockchain::block_info::{BlockInfo, BlockLocation}; + use blockchain::ImportRoute; + + #[test] + fn import_route_none() { + assert_eq!(ImportRoute::none(), ImportRoute { + validated_blocks: vec![], + invalidated_blocks: vec![], + }); + } + + #[test] + fn import_route_branch() { + let info = BlockInfo { + hash: H256::from(U256::from(1)), + number: 0, + total_difficulty: U256::from(0), + location: BlockLocation::Branch, + }; + + assert_eq!(ImportRoute::from(info), ImportRoute::none()); + } + + #[test] + fn import_route_canon_chain() { + let info = BlockInfo { + hash: H256::from(U256::from(1)), + number: 0, + total_difficulty: U256::from(0), + location: BlockLocation::CanonChain, + }; + + assert_eq!(ImportRoute::from(info), ImportRoute { + invalidated_blocks: vec![], + validated_blocks: vec![H256::from(U256::from(1))], + }); + } + + #[test] + fn import_route_branch_becoming_canon_chain() { + let info = BlockInfo { + hash: H256::from(U256::from(2)), + number: 0, + total_difficulty: U256::from(0), + location: BlockLocation::BranchBecomingCanonChain { + ancestor: H256::from(U256::from(0)), + route: vec![H256::from(U256::from(1))], + old_route: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], + } + }; + + assert_eq!(ImportRoute::from(info), ImportRoute { + invalidated_blocks: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], + validated_blocks: vec![H256::from(U256::from(1)), H256::from(U256::from(2))], + }); + } +} diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index b0679b563..6559d8364 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -25,7 +25,9 @@ mod tree_route; mod update; #[cfg(test)] mod generator; +mod import_route; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize; pub use self::tree_route::TreeRoute; +pub use self::import_route::ImportRoute; From d7e729a4eaee966d5ef4ea9b1ac57ac32a0714f9 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 9 Mar 2016 23:55:56 +0100 Subject: [PATCH 454/753] Fixed sync handling large forks --- sync/src/chain.rs | 4 ++-- sync/src/range_collection.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index fe1b559cd..14f6d6344 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -843,8 +843,8 @@ impl ChainSync { self.downloading_bodies.remove(&n); self.downloading_headers.remove(&n); } - self.headers.remove_tail(&start); - self.bodies.remove_tail(&start); + self.headers.remove_from(&start); + self.bodies.remove_from(&start); } /// Request headers from a peer by block hash diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index dc2f4e446..9bb5cc522 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -42,6 +42,8 @@ pub trait RangeCollection { fn remove_head(&mut self, start: &K); /// Remove all elements >= `start` in the range that contains `start` fn remove_tail(&mut self, start: &K); + /// Remove all elements >= `start` + fn remove_from(&mut self, start: &K); /// Remove all elements >= `tail` fn insert_item(&mut self, key: K, value: V); /// Get an iterator over ranges @@ -137,6 +139,28 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } } + /// Remove the element and all following it. + fn remove_from(&mut self, key: &K) { + match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) { + Ok(index) => { self.drain(.. index + 1); }, + Err(index) =>{ + let mut empty = false; + match self.get_mut(index) { + Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => { + v.truncate((*key - *k).to_usize()); + empty = v.is_empty(); + } + _ => {} + } + if empty { + self.drain(.. index + 1); + } else { + self.drain(.. index); + } + }, + } + } + /// Remove range elements up to key fn remove_head(&mut self, key: &K) { if *key == FromUsize::from_usize(0) { @@ -272,5 +296,17 @@ fn test_range() { assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal); r.remove_tail(&2); assert_eq!(r.range_iter().next(), None); + + let mut r = ranges.clone(); + r.remove_from(&20); + assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal); + r.remove_from(&17); + assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p'][..])]), Ordering::Equal); + r.remove_from(&15); + assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..])]), Ordering::Equal); + r.remove_from(&3); + assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal); + r.remove_from(&2); + assert_eq!(r.range_iter().next(), None); } From f397fb210f3ff0695595a28d3dc5483f59b07848 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 10 Mar 2016 00:11:35 +0100 Subject: [PATCH 455/753] fixed typo --- ethcore/src/blockchain/import_route.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs index 10629f2cb..b0d76ef6e 100644 --- a/ethcore/src/blockchain/import_route.rs +++ b/ethcore/src/blockchain/import_route.rs @@ -24,7 +24,7 @@ use blockchain::block_info::{BlockInfo, BlockLocation}; pub struct ImportRoute { /// Blocks that were invalidated by new block. pub invalidated_blocks: Vec, - /// Blocks that were validted by new block. + /// Blocks that were validated by new block. pub validated_blocks: Vec, } From 84a741d0f9ba09bff6a409c077ebacdc531fd561 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 10 Mar 2016 00:21:07 +0100 Subject: [PATCH 456/753] Don't call mark_as_bad needlessly --- ethcore/src/block_queue.rs | 6 ++++++ ethcore/src/client.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 8f1105b8b..c83542f12 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -320,6 +320,9 @@ impl BlockQueue { /// Mark given block and all its children as bad. Stops verification. pub fn mark_as_bad(&mut self, block_hashes: &[H256]) { + if block_hashes.is_empty() { + return; + } let mut verification_lock = self.verification.lock().unwrap(); let mut processing = self.processing.write().unwrap(); @@ -345,6 +348,9 @@ impl BlockQueue { /// Mark given block as processed pub fn mark_as_good(&mut self, block_hashes: &[H256]) { + if block_hashes.is_empty() { + return; + } let mut processing = self.processing.write().unwrap(); for hash in block_hashes { processing.remove(&hash); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 8471666aa..2d9b2e3c5 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -404,8 +404,12 @@ impl Client where V: Verifier { { let mut block_queue = self.block_queue.write().unwrap(); - block_queue.mark_as_bad(&bad_blocks); - block_queue.mark_as_good(&good_blocks); + if !bad_blocks.is_empty() { + block_queue.mark_as_bad(&bad_blocks); + } + if !good_blocks.is_empty() { + block_queue.mark_as_good(&good_blocks); + } } { From 3c1888c26abd94107f20a4a42cabaa3f01fbef53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 09:26:04 +0100 Subject: [PATCH 457/753] Fixing deps --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7df0c2541..1dbe54c8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,14 +25,14 @@ ethcore-util = { path = "util" } ethsync = { path = "sync" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } +number_prefix = "0.2" +rpassword = "0.1" [dev-dependencies] ethcore = { path = "ethcore", features = ["dev"] } ethcore-util = { path = "util", features = ["dev"] } ethsync = { path = "sync", features = ["dev"] } ethcore-rpc = { path = "rpc", features = ["dev"] } -number_prefix = "0.2" -rpassword = "0.1" [features] default = ["rpc"] From 878e38c0cf922fbdd3b51b0f71892418181903ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 09:33:25 +0100 Subject: [PATCH 458/753] Fixing deps again --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1dbe54c8f..e797a3eac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ ethcore-util = { path = "util" } ethsync = { path = "sync" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } -number_prefix = "0.2" rpassword = "0.1" [dev-dependencies] From 9f77a85491b714ee03de491471c23b2714548cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 09:35:46 +0100 Subject: [PATCH 459/753] Fixing compilation on nightly --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e797a3eac..22d0f9288 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ rpc = ["ethcore-rpc"] dev = ["ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] dev-clippy = ["clippy", "ethcore/clippy", "ethcore-util/clippy", "ethsync/clippy", "ethcore-rpc/clippy"] travis-beta = ["ethcore/json-tests"] -travis-nightly = ["ethcore/json-tests", "clippy", "dev"] +travis-nightly = ["ethcore/json-tests", "dev-clippy", "dev"] [[bin]] path = "parity/main.rs" From ca2cf8e591404245fed40cc1f8d81f8a6e67087e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 10:05:51 +0100 Subject: [PATCH 460/753] Lowering minimal gas price --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index b3a0224d8..4cf52728e 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -108,7 +108,7 @@ API and Console Options: --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). Sealing/Mining Options: - --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 50000000000]. + --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 20000000000]. --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. From 02b7e7698ad07fccb61aa5f51b31e47ad599c851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 10:09:55 +0100 Subject: [PATCH 461/753] Breaking couple of lines to keep number of characters below limit --- parity/main.rs | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 4cf52728e..729f6aeed 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -247,12 +247,15 @@ impl Configuration { } fn author(&self) -> Address { - Address::from_str(&self.args.flag_author).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) + Address::from_str(&self.args.flag_author).unwrap_or_else(|_| { + die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author) + }) } fn gasprice(&self) -> U256 { - U256::from_dec_str(self.args.flag_gasprice).unwrap_or_else(|_| die("{}: Invalid gasprice given. Must be a - decimal unsigned 256-bit number.")) + U256::from_dec_str(self.args.flag_gasprice).unwrap_or_else(|_| { + die("{}: Invalid gasprice given. Must be a decimal unsigned 256-bit number.") + }) } fn extra_data(&self) -> Bytes { @@ -275,7 +278,9 @@ impl Configuration { "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(), "morden" | "testnet" => ethereum::new_morden(), "olympic" => ethereum::new_olympic(), - f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| die!("{}: Couldn't read chain specification file. Sure it exists?", f)).as_ref()), + f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| { + die!("{}: Couldn't read chain specification file. Sure it exists?", f) + }).as_ref()), } } @@ -291,7 +296,9 @@ impl Configuration { if self.args.flag_no_bootstrap { Vec::new() } else { match self.args.arg_enode.len() { 0 => spec.nodes().clone(), - _ => self.args.arg_enode.iter().map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s))).collect(), + _ => self.args.arg_enode.iter().map(|s| Self::normalize_enode(s).unwrap_or_else(|| { + die!("{}: Invalid node address format given for a boot node.", s) + })).collect(), } } } @@ -302,17 +309,23 @@ impl Configuration { let mut public_address = None; if let Some(ref a) = self.args.flag_address { - public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --address", a))); + public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| { + die!("{}: Invalid listen/public address given with --address", a) + })); listen_address = public_address; } if listen_address.is_none() { - listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --listen-address", self.args.flag_listen_address))); + listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).unwrap_or_else(|_| { + die!("{}: Invalid listen/public address given with --listen-address", self.args.flag_listen_address) + })); } if let Some(ref a) = self.args.flag_public_address { if public_address.is_some() { die!("Conflicting flags provided: --address and --public-address"); } - public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --public-address", a))); + public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| { + die!("{}: Invalid listen/public address given with --public-address", a) + })); } (listen_address, public_address) } @@ -403,7 +416,7 @@ impl Configuration { self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_addr), self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) ); - SocketAddr::from_str(&url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen host/port given.", url)); + SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); @@ -475,7 +488,11 @@ impl Informant { let report = client.report(); let sync_info = sync.status(); - if let (_, _, &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { + if let (_, _, &Some(ref last_report)) = ( + self.chain_info.read().unwrap().deref(), + self.cache_info.read().unwrap().deref(), + self.report.read().unwrap().deref() + ) { println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} db, {} chain, {} queue, {} sync ]", chain_info.best_block_number, chain_info.best_block_hash, From 0a7cda09ffc9ec876599b23f2955763ab0ae6539 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 10 Mar 2016 10:17:17 +0100 Subject: [PATCH 462/753] changed route name to enacted and retracted --- ethcore/src/blockchain/block_info.rs | 4 +-- ethcore/src/blockchain/blockchain.rs | 30 ++++++++++----------- ethcore/src/blockchain/import_route.rs | 36 +++++++++++++------------- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index 335bdbb4e..cf16a8834 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -44,8 +44,8 @@ pub enum BlockLocation { /// Hash of the newest common ancestor with old canon chain. ancestor: H256, /// Hashes of the blocks between ancestor and this block. - route: Vec, + enacted: Vec, /// Hashes of the blocks which were invalidated. - old_route: Vec, + retracted: Vec, } } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index e57f7208a..d67c1b7f1 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -552,12 +552,12 @@ impl BlockChain { match route.blocks.len() { 0 => BlockLocation::CanonChain, _ => { - let old_route = route.blocks.iter().take(route.index).cloned().collect::>(); + let retracted = route.blocks.iter().take(route.index).cloned().collect::>(); BlockLocation::BranchBecomingCanonChain { ancestor: route.ancestor, - route: route.blocks.into_iter().skip(route.index).collect(), - old_route: old_route.into_iter().rev().collect(), + enacted: route.blocks.into_iter().skip(route.index).collect(), + retracted: retracted.into_iter().rev().collect(), } } } @@ -579,11 +579,11 @@ impl BlockChain { BlockLocation::CanonChain => { block_hashes.insert(number, info.hash.clone()); }, - BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route, .. } => { + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => { let ancestor_number = self.block_number(ancestor).unwrap(); let start_number = ancestor_number + 1; - for (index, hash) in route.iter().cloned().enumerate() { + for (index, hash) in enacted.iter().cloned().enumerate() { block_hashes.insert(start_number + index as BlockNumber, hash); } @@ -668,11 +668,11 @@ impl BlockChain { ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) .add_bloom(&header.log_bloom(), header.number() as usize) }, - BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route, .. } => { + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => { let ancestor_number = self.block_number(ancestor).unwrap(); let start_number = ancestor_number + 1; - let mut blooms: Vec = route.iter() + let mut blooms: Vec = enacted.iter() .map(|hash| self.block(hash).unwrap()) .map(|bytes| BlockView::new(&bytes).header_view().log_bloom()) .collect(); @@ -956,23 +956,23 @@ mod tests { let ir3a = bc.insert_block(&b3a, vec![]); assert_eq!(ir1, ImportRoute { - validated_blocks: vec![b1_hash], - invalidated_blocks: vec![], + enacted: vec![b1_hash], + retracted: vec![], }); assert_eq!(ir2, ImportRoute { - validated_blocks: vec![b2_hash], - invalidated_blocks: vec![], + enacted: vec![b2_hash], + retracted: vec![], }); assert_eq!(ir3b, ImportRoute { - validated_blocks: vec![b3b_hash], - invalidated_blocks: vec![], + enacted: vec![b3b_hash], + retracted: vec![], }); assert_eq!(ir3a, ImportRoute { - validated_blocks: vec![b3a_hash], - invalidated_blocks: vec![b3b_hash], + enacted: vec![b3a_hash], + retracted: vec![b3b_hash], }); assert_eq!(bc.best_block_hash(), best_block_hash); diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs index b0d76ef6e..262b70899 100644 --- a/ethcore/src/blockchain/import_route.rs +++ b/ethcore/src/blockchain/import_route.rs @@ -23,16 +23,16 @@ use blockchain::block_info::{BlockInfo, BlockLocation}; #[derive(Debug, PartialEq)] pub struct ImportRoute { /// Blocks that were invalidated by new block. - pub invalidated_blocks: Vec, + pub retracted: Vec, /// Blocks that were validated by new block. - pub validated_blocks: Vec, + pub enacted: Vec, } impl ImportRoute { pub fn none() -> Self { ImportRoute { - invalidated_blocks: vec![], - validated_blocks: vec![], + retracted: vec![], + enacted: vec![], } } } @@ -41,15 +41,15 @@ impl From for ImportRoute { fn from(info: BlockInfo) -> ImportRoute { match info.location { BlockLocation::CanonChain => ImportRoute { - invalidated_blocks: vec![], - validated_blocks: vec![info.hash], + retracted: vec![], + enacted: vec![info.hash], }, BlockLocation::Branch => ImportRoute::none(), - BlockLocation::BranchBecomingCanonChain { mut route, old_route, .. } => { - route.push(info.hash); + BlockLocation::BranchBecomingCanonChain { mut enacted, retracted, .. } => { + enacted.push(info.hash); ImportRoute { - invalidated_blocks: old_route, - validated_blocks: route, + retracted: retracted, + enacted: enacted, } } } @@ -66,8 +66,8 @@ mod tests { #[test] fn import_route_none() { assert_eq!(ImportRoute::none(), ImportRoute { - validated_blocks: vec![], - invalidated_blocks: vec![], + enacted: vec![], + retracted: vec![], }); } @@ -93,8 +93,8 @@ mod tests { }; assert_eq!(ImportRoute::from(info), ImportRoute { - invalidated_blocks: vec![], - validated_blocks: vec![H256::from(U256::from(1))], + retracted: vec![], + enacted: vec![H256::from(U256::from(1))], }); } @@ -106,14 +106,14 @@ mod tests { total_difficulty: U256::from(0), location: BlockLocation::BranchBecomingCanonChain { ancestor: H256::from(U256::from(0)), - route: vec![H256::from(U256::from(1))], - old_route: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], + enacted: vec![H256::from(U256::from(1))], + retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], } }; assert_eq!(ImportRoute::from(info), ImportRoute { - invalidated_blocks: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], - validated_blocks: vec![H256::from(U256::from(1)), H256::from(U256::from(2))], + retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], + enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))], }); } } From a2046b429f9120a0532dc1da3fc4467fa20c6469 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 13:27:33 +0400 Subject: [PATCH 463/753] exposing only one func --- sync/src/chain.rs | 9 +++++++-- sync/src/lib.rs | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 7294570fe..ea9a47da2 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -43,6 +43,7 @@ use io::SyncIo; use transaction_queue::TransactionQueue; use time; use super::SyncConfig; +use ethcore; known_heap_size!(0, PeerInfo, Header, HeaderId); @@ -1300,8 +1301,12 @@ impl ChainSync { // TODO [todr] propagate transactions? } - pub fn transaction_queue(&self) -> &Mutex { - return &self.transaction_queue; + /// Add transaction to the transaction queue + pub fn insert_transaction(&self, transaction: ethcore::transaction::SignedTransaction, fetch_nonce: &T) + where T: Fn(&Address) -> U256 + { + let mut queue = self.transaction_queue.lock().unwrap(); + queue.add(transaction, fetch_nonce); } } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index fdcf79749..c9eb792a1 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -135,8 +135,7 @@ impl EthSync { let nonce_fn = |a: &Address| self.chain.state().nonce(a) + U256::one(); let sync = self.sync.write().unwrap(); - let mut queue = sync.transaction_queue().lock().unwrap(); - queue.add(transaction, &nonce_fn); + sync.insert_transaction(transaction, &nonce_fn); } } From ff12b53ba69899dd4a700ff58720bdf6d29ca22c Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 10 Mar 2016 10:40:16 +0100 Subject: [PATCH 464/753] Stop workers before stopping event loop --- util/src/io/service.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/util/src/io/service.rs b/util/src/io/service.rs index 83fa71b8a..8a34ee80a 100644 --- a/util/src/io/service.rs +++ b/util/src/io/service.rs @@ -153,7 +153,7 @@ struct UserTimer { pub struct IoManager where Message: Send + Sync { timers: Arc>>, handlers: Vec>>, - _workers: Vec, + workers: Vec, worker_channel: chase_lev::Worker>, work_ready: Arc, } @@ -180,7 +180,7 @@ impl IoManager where Message: Send + Sync + Clone + 'static { timers: Arc::new(RwLock::new(HashMap::new())), handlers: Vec::new(), worker_channel: worker, - _workers: workers, + workers: workers, work_ready: work_ready, }; try!(event_loop.run(&mut io)); @@ -230,7 +230,10 @@ impl Handler for IoManager where Message: Send + Clone + Sync fn notify(&mut self, event_loop: &mut EventLoop, msg: Self::Message) { match msg { - IoMessage::Shutdown => event_loop.shutdown(), + IoMessage::Shutdown => { + self.workers.clear(); + event_loop.shutdown(); + }, IoMessage::AddHandler { handler } => { let handler_id = { self.handlers.push(handler.clone()); From 90ae7500da814df956e7b2fb228c1a15711c5886 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 10 Mar 2016 11:07:10 +0100 Subject: [PATCH 465/753] Update main.rs --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 729f6aeed..745912028 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -108,7 +108,7 @@ API and Console Options: --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). Sealing/Mining Options: - --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 20000000000]. + --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 20000000000]. --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. From 276768a82600045a2f95767d5d5c6dbb72873753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 11:11:59 +0100 Subject: [PATCH 466/753] Failing test case for #656 --- sync/src/transaction_queue.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 3e0d931b5..38e70d1fc 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -541,6 +541,28 @@ mod test { assert_eq!(top[0], tx); } + #[test] + fn should_correctly_update_futures_when_removing() { + // given + let prev_nonce = |a: &Address| default_nonce(a) - U256::one(); + let next2_nonce = |a: &Address| default_nonce(a) + U256::from(2); + + let mut txq = TransactionQueue::new(); + + let (tx, tx2) = new_txs(U256::from(1)); + txq.add(tx.clone(), &prev_nonce); + txq.add(tx2.clone(), &prev_nonce); + assert_eq!(txq.status().future, 2); + + // when + txq.remove(&tx.hash(), &next2_nonce); + // should remove both transactions since they are not valid + + // then + assert_eq!(txq.status().pending, 0); + assert_eq!(txq.status().future, 0); + } + #[test] fn should_move_transactions_if_gap_filled() { // given From 0cf405527e80879a6e97fae68707b86ec67403be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 11:14:25 +0100 Subject: [PATCH 467/753] Fixing update height bug --- sync/src/transaction_queue.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 38e70d1fc..ac8debfc9 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -277,7 +277,12 @@ impl TransactionQueue { }; for k in all_nonces_from_sender { let order = self.future.drop(&sender, &k).unwrap(); - self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); + if k >= current_nonce { + self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); + } else { + // Remove the transaction completely + self.by_hash.remove(&order.hash); + } } } From 6d0578e19c5b5442ccdb42d695fb6a70238cf6ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 11:16:54 +0100 Subject: [PATCH 468/753] Additional explanation for ordering of commit/insert_block --- ethcore/src/client.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 874fc9646..aaf5fd728 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -396,7 +396,8 @@ impl Client where V: Verifier { .commit(header.number(), &header.hash(), ancient) .expect("State DB commit failed."); - // And update the chain + // And update the chain after commit to prevent race conditions + // (when something is in chain but you are not able to fetch details) self.chain.write().unwrap() .insert_block(&block.bytes, receipts); From 6681aaf76af521a4c67bfa4d85fbaedaa4029915 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 10 Mar 2016 11:32:10 +0100 Subject: [PATCH 469/753] split client into few submodules --- ethcore/src/{ => client}/client.rs | 123 ++--------------------------- ethcore/src/client/config.rs | 31 ++++++++ ethcore/src/client/ids.rs | 44 +++++++++++ ethcore/src/client/mod.rs | 102 ++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 117 deletions(-) rename ethcore/src/{ => client}/client.rs (85%) create mode 100644 ethcore/src/client/config.rs create mode 100644 ethcore/src/client/ids.rs create mode 100644 ethcore/src/client/mod.rs diff --git a/ethcore/src/client.rs b/ethcore/src/client/client.rs similarity index 85% rename from ethcore/src/client.rs rename to ethcore/src/client/client.rs index b342cef15..2f9536b2e 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client/client.rs @@ -20,7 +20,6 @@ use std::marker::PhantomData; use std::sync::atomic::AtomicBool; use util::*; use util::panics::*; -use blockchain::{BlockChain, BlockProvider}; use views::BlockView; use error::*; use header::{BlockNumber}; @@ -28,7 +27,6 @@ use state::State; use spec::Spec; use engine::Engine; use views::HeaderView; -use block_queue::BlockQueue; use service::{NetSyncMessage, SyncMessage}; use env_info::LastHashes; use verification::*; @@ -38,32 +36,9 @@ use extras::TransactionAddress; use filter::Filter; use log_entry::LocalizedLogEntry; use util::keys::store::SecretStore; -pub use block_queue::{BlockQueueConfig, BlockQueueInfo}; -pub use blockchain::{TreeRoute, BlockChainConfig, CacheSize as BlockChainCacheSize}; - -/// Uniquely identifies block. -#[derive(Debug, PartialEq, Clone)] -pub enum BlockId { - /// Block's sha3. - /// Querying by hash is always faster. - Hash(H256), - /// Block number within canon blockchain. - Number(BlockNumber), - /// Earliest block (genesis). - Earliest, - /// Latest mined block. - Latest -} - -/// Uniquely identifies transaction. -#[derive(Debug, PartialEq, Clone)] -pub enum TransactionId { - /// Transaction's sha3. - Hash(H256), - /// Block id and transaction index within this block. - /// Querying by block position is always faster. - Location(BlockId, usize) -} +use block_queue::{BlockQueue, BlockQueueInfo}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, CacheSize as BlockChainCacheSize}; +use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; /// General block status #[derive(Debug, Eq, PartialEq)] @@ -78,30 +53,6 @@ pub enum BlockStatus { Unknown, } -/// Client configuration. Includes configs for all sub-systems. -#[derive(Debug)] -pub struct ClientConfig { - /// Block queue configuration. - pub queue: BlockQueueConfig, - /// Blockchain configuration. - pub blockchain: BlockChainConfig, - /// Prefer journal rather than archive. - pub prefer_journal: bool, - /// The name of the client instance. - pub name: String, -} - -impl Default for ClientConfig { - fn default() -> ClientConfig { - ClientConfig { - queue: Default::default(), - blockchain: Default::default(), - prefer_journal: false, - name: Default::default(), - } - } -} - /// Information about the blockchain gathered together. #[derive(Debug)] pub struct BlockChainInfo { @@ -123,72 +74,8 @@ impl fmt::Display for BlockChainInfo { } } -/// Blockchain database client. Owns and manages a blockchain and a block queue. -pub trait BlockChainClient : Sync + Send { - /// Get raw block header data by block id. - fn block_header(&self, id: BlockId) -> Option; - - /// Get raw block body data by block id. - /// Block body is an RLP list of two items: uncles and transactions. - fn block_body(&self, id: BlockId) -> Option; - - /// Get raw block data by block header hash. - fn block(&self, id: BlockId) -> Option; - - /// Get block status by block header hash. - fn block_status(&self, id: BlockId) -> BlockStatus; - - /// Get block total difficulty. - fn block_total_difficulty(&self, id: BlockId) -> Option; - - /// Get address nonce. - fn nonce(&self, address: &Address) -> U256; - - /// Get block hash. - fn block_hash(&self, id: BlockId) -> Option; - - /// Get address code. - fn code(&self, address: &Address) -> Option; - - /// Get transaction with given hash. - fn transaction(&self, id: TransactionId) -> Option; - - /// Get a tree route between `from` and `to`. - /// See `BlockChain::tree_route`. - fn tree_route(&self, from: &H256, to: &H256) -> Option; - - /// Get latest state node - fn state_data(&self, hash: &H256) -> Option; - - /// Get raw block receipts data by block header hash. - fn block_receipts(&self, hash: &H256) -> Option; - - /// Import a block into the blockchain. - fn import_block(&self, bytes: Bytes) -> ImportResult; - - /// Get block queue information. - fn queue_info(&self) -> BlockQueueInfo; - - /// Clear block queue and abort all import activity. - fn clear_queue(&self); - - /// Get blockchain information. - fn chain_info(&self) -> BlockChainInfo; - - /// Get the best block header. - fn best_block_header(&self) -> Bytes { - self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() - } - - /// Returns numbers of blocks containing given bloom. - fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option>; - - /// Returns logs matching given filter. - fn logs(&self, filter: Filter) -> Vec; -} - -#[derive(Default, Clone, Debug, Eq, PartialEq)] /// Report on the status of a client. +#[derive(Default, Clone, Debug, Eq, PartialEq)] pub struct ClientReport { /// How many blocks have been imported so far. pub blocks_imported: usize, @@ -679,6 +566,8 @@ impl BlockChainClient for Client where V: Verifier { } fn logs(&self, filter: Filter) -> Vec { + // TODO: lock blockchain only once + let mut blocks = filter.bloom_possibilities().iter() .filter_map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone())) .flat_map(|m| m) diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs new file mode 100644 index 000000000..484c8d0c6 --- /dev/null +++ b/ethcore/src/client/config.rs @@ -0,0 +1,31 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +pub use block_queue::BlockQueueConfig; +pub use blockchain::BlockChainConfig; + +/// Client configuration. Includes configs for all sub-systems. +#[derive(Debug, Default)] +pub struct ClientConfig { + /// Block queue configuration. + pub queue: BlockQueueConfig, + /// Blockchain configuration. + pub blockchain: BlockChainConfig, + /// Prefer journal rather than archive. + pub prefer_journal: bool, + /// The name of the client instance. + pub name: String, +} diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs new file mode 100644 index 000000000..303657a76 --- /dev/null +++ b/ethcore/src/client/ids.rs @@ -0,0 +1,44 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Unique identifiers. + +use util::hash::H256; +use header::BlockNumber; + +/// Uniquely identifies block. +#[derive(Debug, PartialEq, Clone)] +pub enum BlockId { + /// Block's sha3. + /// Querying by hash is always faster. + Hash(H256), + /// Block number within canon blockchain. + Number(BlockNumber), + /// Earliest block (genesis). + Earliest, + /// Latest mined block. + Latest +} + +/// Uniquely identifies transaction. +#[derive(Debug, PartialEq, Clone)] +pub enum TransactionId { + /// Transaction's sha3. + Hash(H256), + /// Block id and transaction index within this block. + /// Querying by block position is always faster. + Location(BlockId, usize) +} diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs new file mode 100644 index 000000000..0daa17553 --- /dev/null +++ b/ethcore/src/client/mod.rs @@ -0,0 +1,102 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain database client. + +mod client; +mod config; +mod ids; + +pub use self::client::*; +pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; +pub use self::ids::{BlockId, TransactionId}; + +use util::bytes::Bytes; +use util::hash::{Address, H256, H2048}; +use util::numbers::U256; +use blockchain::TreeRoute; +use block_queue::BlockQueueInfo; +use header::BlockNumber; +use transaction::LocalizedTransaction; +use log_entry::LocalizedLogEntry; +use filter::Filter; +use error::ImportResult; + +/// Blockchain database client. Owns and manages a blockchain and a block queue. +pub trait BlockChainClient : Sync + Send { + /// Get raw block header data by block id. + fn block_header(&self, id: BlockId) -> Option; + + /// Get raw block body data by block id. + /// Block body is an RLP list of two items: uncles and transactions. + fn block_body(&self, id: BlockId) -> Option; + + /// Get raw block data by block header hash. + fn block(&self, id: BlockId) -> Option; + + /// Get block status by block header hash. + fn block_status(&self, id: BlockId) -> BlockStatus; + + /// Get block total difficulty. + fn block_total_difficulty(&self, id: BlockId) -> Option; + + /// Get address nonce. + fn nonce(&self, address: &Address) -> U256; + + /// Get block hash. + fn block_hash(&self, id: BlockId) -> Option; + + /// Get address code. + fn code(&self, address: &Address) -> Option; + + /// Get transaction with given hash. + fn transaction(&self, id: TransactionId) -> Option; + + /// Get a tree route between `from` and `to`. + /// See `BlockChain::tree_route`. + fn tree_route(&self, from: &H256, to: &H256) -> Option; + + /// Get latest state node + fn state_data(&self, hash: &H256) -> Option; + + /// Get raw block receipts data by block header hash. + fn block_receipts(&self, hash: &H256) -> Option; + + /// Import a block into the blockchain. + fn import_block(&self, bytes: Bytes) -> ImportResult; + + /// Get block queue information. + fn queue_info(&self) -> BlockQueueInfo; + + /// Clear block queue and abort all import activity. + fn clear_queue(&self); + + /// Get blockchain information. + fn chain_info(&self) -> BlockChainInfo; + + /// Get the best block header. + fn best_block_header(&self) -> Bytes { + // TODO: lock blockchain only once + self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() + } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option>; + + /// Returns logs matching given filter. + fn logs(&self, filter: Filter) -> Vec; +} + From eb1fab92024779aa91d4c83844677347b0b071e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 12:33:29 +0100 Subject: [PATCH 470/753] Adding clippy support to ethminer. --- miner/Cargo.toml | 4 ++++ miner/build.rs | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 miner/build.rs diff --git a/miner/Cargo.toml b/miner/Cargo.toml index fb3f24210..713182563 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -5,6 +5,10 @@ license = "GPL-3.0" name = "ethminer" version = "0.9.99" authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +rustc_version = "0.1" [dependencies] ethcore-util = { path = "../util" } diff --git a/miner/build.rs b/miner/build.rs new file mode 100644 index 000000000..41b9a1b3e --- /dev/null +++ b/miner/build.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } +} From 9db4720162a2d46e81d1d595c0a052c0e2452f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 14:06:47 +0100 Subject: [PATCH 471/753] Fixing clippy warnings. --- miner/src/miner.rs | 10 +++++----- miner/src/transaction_queue.rs | 28 ++++++++++++++-------------- parity/main.rs | 4 ++-- sync/src/chain.rs | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 2c18f3a79..8e93defcf 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -31,7 +31,7 @@ pub trait MinerService { fn status(&self) -> MinerStatus; /// Imports transactions to transaction queue. - fn import_transactions(&self, transactions: Vec, fetch_nonce: T) + fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256; /// Removes all transactions from the queue and restart mining operation. @@ -129,10 +129,10 @@ impl MinerService for Miner { } } - fn import_transactions(&self, transactions: Vec, fetch_nonce: T) + fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256 { let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(transactions, fetch_nonce); + transaction_queue.add_all(transactions, fetch_nonce) } fn prepare_sealing(&self, chain: &BlockChainClient) { @@ -180,7 +180,7 @@ impl MinerService for Miner { fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]) { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { let block = chain - .block(BlockId::Hash(hash.clone())) + .block(BlockId::Hash(*hash)) // Client should send message after commit to db and inserting to chain. .expect("Expected in-chain blocks."); let block = BlockView::new(&block); @@ -202,7 +202,7 @@ impl MinerService for Miner { let _sender = tx.sender(); } let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(txs, |a| chain.nonce(a)); + let _ = transaction_queue.add_all(txs, |a| chain.nonce(a)); }); } diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 81825773f..f64bd7318 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -360,7 +360,7 @@ impl TransactionQueue { self.update_future(&sender, current_nonce); // And now lets check if there is some chain of transactions in future // that should be placed in current - self.move_matching_future_to_current(sender.clone(), current_nonce, current_nonce); + self.move_matching_future_to_current(sender, current_nonce, current_nonce); return; } @@ -376,7 +376,7 @@ impl TransactionQueue { self.move_all_to_future(&sender, current_nonce); // And now lets check if there is some chain of transactions in future // that should be placed in current. It should also update last_nonces. - self.move_matching_future_to_current(sender.clone(), current_nonce, current_nonce); + self.move_matching_future_to_current(sender, current_nonce, current_nonce); return; } } @@ -391,7 +391,7 @@ impl TransactionQueue { for k in all_nonces_from_sender { let order = self.future.drop(&sender, &k).unwrap(); if k >= current_nonce { - self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); + self.future.insert(*sender, k, order.update_height(k, current_nonce)); } else { // Remove the transaction completely self.by_hash.remove(&order.hash); @@ -411,7 +411,7 @@ impl TransactionQueue { // Goes to future or is removed let order = self.current.drop(&sender, &k).unwrap(); if k >= current_nonce { - self.future.insert(sender.clone(), k, order.update_height(k, current_nonce)); + self.future.insert(*sender, k, order.update_height(k, current_nonce)); } else { self.by_hash.remove(&order.hash); } @@ -452,8 +452,8 @@ impl TransactionQueue { // remove also from priority and hash self.future.by_priority.remove(&order); // Put to current - let order = order.update_height(current_nonce.clone(), first_nonce); - self.current.insert(address.clone(), current_nonce, order); + let order = order.update_height(current_nonce, first_nonce); + self.current.insert(address, current_nonce, order); current_nonce = current_nonce + U256::one(); } } @@ -501,10 +501,10 @@ impl TransactionQueue { } let base_nonce = fetch_nonce(&address); - Self::replace_transaction(tx, base_nonce.clone(), &mut self.current, &mut self.by_hash); - self.last_nonces.insert(address.clone(), nonce); + Self::replace_transaction(tx, base_nonce, &mut self.current, &mut self.by_hash); + self.last_nonces.insert(address, nonce); // But maybe there are some more items waiting in future? - self.move_matching_future_to_current(address.clone(), nonce + U256::one(), base_nonce); + self.move_matching_future_to_current(address, nonce + U256::one(), base_nonce); self.current.enforce_limit(&mut self.by_hash); } @@ -518,7 +518,7 @@ impl TransactionQueue { let address = tx.sender(); let nonce = tx.nonce(); - by_hash.insert(hash.clone(), tx); + by_hash.insert(hash, tx); if let Some(old) = set.insert(address, nonce, order.clone()) { // There was already transaction in queue. Let's check which one should stay let old_fee = old.gas_price; @@ -642,7 +642,7 @@ mod test { txq.set_minimal_gas_price(tx.gas_price + U256::one()); // when - txq.add(tx, &default_nonce); + txq.add(tx, &default_nonce).unwrap_err(); // then let stats = txq.status(); @@ -722,8 +722,8 @@ mod test { let mut txq = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(1)); - txq.add(tx.clone(), &prev_nonce); - txq.add(tx2.clone(), &prev_nonce); + txq.add(tx.clone(), &prev_nonce).unwrap(); + txq.add(tx2.clone(), &prev_nonce).unwrap(); assert_eq!(txq.status().future, 2); // when @@ -861,7 +861,7 @@ mod test { fn should_drop_transactions_with_old_nonces() { let mut txq = TransactionQueue::new(); let tx = new_tx(); - let last_nonce = tx.nonce.clone() + U256::one(); + let last_nonce = tx.nonce + U256::one(); let fetch_last_nonce = |_a: &Address| last_nonce; // when diff --git a/parity/main.rs b/parity/main.rs index 9dbc3e6be..c73f971d9 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -259,8 +259,8 @@ impl Configuration { } fn gasprice(&self) -> U256 { - U256::from_dec_str(self.args.flag_gasprice).unwrap_or_else(|_| { - die("{}: Invalid gasprice given. Must be a decimal unsigned 256-bit number.") + U256::from_dec_str(self.args.flag_gasprice.as_str()).unwrap_or_else(|_| { + die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", self.args.flag_gasprice) }) } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 46eaebe4c..85f5d6510 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -936,7 +936,7 @@ impl ChainSync { } let chain = io.chain(); let fetch_nonce = |a: &Address| chain.nonce(a); - self.miner.import_transactions(transactions, fetch_nonce); + let _ = self.miner.import_transactions(transactions, fetch_nonce); Ok(()) } From 027f122aea154b14c7563386251ff0407b4d2969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 14:24:33 +0100 Subject: [PATCH 472/753] Removing get prefix from poll_info --- rpc/src/v1/helpers/poll_manager.rs | 18 +++++++++--------- rpc/src/v1/impls/eth.rs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index 36a6352c2..0297384d1 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -84,7 +84,7 @@ impl PollManager where T: Timer { } /// Returns number of block when last poll happend. - pub fn get_poll_info(&mut self, id: &PollId) -> Option<&PollInfo> { + pub fn poll_info(&mut self, id: &PollId) -> Option<&PollInfo> { self.polls.prune(); self.polls.get(id) } @@ -124,21 +124,21 @@ mod tests { *time.borrow_mut() = 10; indexer.update_poll(&0, 21); - assert_eq!(indexer.get_poll_info(&0).unwrap().filter, false); - assert_eq!(indexer.get_poll_info(&0).unwrap().block_number, 21); + assert_eq!(indexer.poll_info(&0).unwrap().filter, false); + assert_eq!(indexer.poll_info(&0).unwrap().block_number, 21); *time.borrow_mut() = 30; indexer.update_poll(&1, 23); - assert_eq!(indexer.get_poll_info(&1).unwrap().filter, true); - assert_eq!(indexer.get_poll_info(&1).unwrap().block_number, 23); + assert_eq!(indexer.poll_info(&1).unwrap().filter, true); + assert_eq!(indexer.poll_info(&1).unwrap().block_number, 23); *time.borrow_mut() = 75; indexer.update_poll(&0, 30); - assert!(indexer.get_poll_info(&0).is_none()); - assert_eq!(indexer.get_poll_info(&1).unwrap().filter, true); - assert_eq!(indexer.get_poll_info(&1).unwrap().block_number, 23); + assert!(indexer.poll_info(&0).is_none()); + assert_eq!(indexer.poll_info(&1).unwrap().filter, true); + assert_eq!(indexer.poll_info(&1).unwrap().block_number, 23); indexer.remove_poll(&1); - assert!(indexer.get_poll_info(&1).is_none()); + assert!(indexer.poll_info(&1).is_none()); } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 7113c55b1..479bae95b 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -307,7 +307,7 @@ impl EthFilter for EthFilterClient { let client = take_weak!(self.client); from_params::<(Index,)>(params) .and_then(|(index,)| { - let info = self.polls.lock().unwrap().get_poll_info(&index.value()).cloned(); + let info = self.polls.lock().unwrap().poll_info(&index.value()).cloned(); match info { None => Ok(Value::Array(vec![] as Vec)), Some(info) => match info.filter { From 9ea3c0eba00efc5c7e13abc26ac2b7f7a5490ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 15:20:54 +0100 Subject: [PATCH 473/753] Fixing compilation on beta & stable --- miner/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 4fccc6d51..0cee4ef43 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(feature="dev", feature(plugin))] -#![cfg_attr(feature="dev", plugin(clippy))] +#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] +#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] //! Miner module //! Keeps track of transactions and mined block. From 9741d48496171b387732ca37a2b8f222fbc3983a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 15:35:36 +0100 Subject: [PATCH 474/753] Transaction data associated with polls. --- rpc/src/v1/helpers/poll_manager.rs | 104 +++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index 36a6352c2..6c0862633 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -16,6 +16,8 @@ //! Indexes all rpc poll requests. +use util::hash::H256; +use std::collections::HashMap; use transient_hashmap::{TransientHashMap, Timer, StandardTimer}; /// Lifetime of poll (in seconds). @@ -43,7 +45,8 @@ impl Clone for PollInfo where F: Clone { /// Lazily garbage collects unused polls info. pub struct PollManager where T: Timer { polls: TransientHashMap, T>, - next_available_id: PollId + transactions_data: HashMap>, + next_available_id: PollId, } impl PollManager { @@ -57,15 +60,25 @@ impl PollManager where T: Timer { pub fn new_with_timer(timer: T) -> Self { PollManager { polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), + transactions_data: HashMap::new(), next_available_id: 0, } } + fn prune(&mut self) { + self.polls.prune(); + // self.polls.prune() + // .into_iter() + // .map(|key| { + // self.transactions_data.remove(key); + // }); + } + /// Returns id which can be used for new poll. /// /// Stores information when last poll happend. pub fn create_poll(&mut self, filter: F, block: BlockNumber) -> PollId { - self.polls.prune(); + self.prune(); let id = self.next_available_id; self.next_available_id += 1; self.polls.insert(id, PollInfo { @@ -77,7 +90,7 @@ impl PollManager where T: Timer { /// Updates information when last poll happend. pub fn update_poll(&mut self, id: &PollId, block: BlockNumber) { - self.polls.prune(); + self.prune(); if let Some(info) = self.polls.get_mut(id) { info.block_number = block; } @@ -85,13 +98,27 @@ impl PollManager where T: Timer { /// Returns number of block when last poll happend. pub fn get_poll_info(&mut self, id: &PollId) -> Option<&PollInfo> { - self.polls.prune(); + self.prune(); self.polls.get(id) } + pub fn set_poll_transactions(&mut self, id: &PollId, transactions: Vec) { + self.prune(); + if self.polls.get(id).is_some() { + self.transactions_data.insert(*id, transactions); + } + } + + /// Returns last transactions hashes for given poll. + pub fn poll_transactions(&mut self, id: &PollId) -> Option<&Vec> { + self.prune(); + self.transactions_data.get(id) + } + /// Removes poll info. pub fn remove_poll(&mut self, id: &PollId) { self.polls.remove(id); + self.transactions_data.remove(id); } } @@ -100,6 +127,7 @@ mod tests { use std::cell::RefCell; use transient_hashmap::Timer; use v1::helpers::PollManager; + use util::hash::H256; struct TestTimer<'a> { time: &'a RefCell, @@ -141,4 +169,72 @@ mod tests { indexer.remove_poll(&1); assert!(indexer.get_poll_info(&1).is_none()); } + + #[test] + fn should_return_poll_transactions_hashes() { + // given + let mut indexer = PollManager::new(); + let poll_id = indexer.create_poll(false, 20); + assert!(indexer.poll_transactions(&poll_id).is_none()); + let transactions = vec![H256::from(1), H256::from(2)]; + + // when + indexer.set_poll_transactions(&poll_id, transactions.clone()); + + // then + let txs = indexer.poll_transactions(&poll_id); + assert_eq!(txs.unwrap(), &transactions); + } + + + #[test] + fn should_remove_transaction_data_when_poll_timed_out() { + // given + let time = RefCell::new(0); + let timer = TestTimer { + time: &time, + }; + let mut indexer = PollManager::new_with_timer(timer); + let poll_id = indexer.create_poll(false, 20); + let transactions = vec![H256::from(1), H256::from(2)]; + indexer.set_poll_transactions(&poll_id, transactions.clone()); + assert!(indexer.poll_transactions(&poll_id).is_some()); + + // when + *time.borrow_mut() = 75; + indexer.prune(); + + // then + assert!(indexer.poll_transactions(&poll_id).is_none()); + + } + + #[test] + fn should_remove_transaction_data_when_poll_is_removed() { + // given + let mut indexer = PollManager::new(); + let poll_id = indexer.create_poll(false, 20); + let transactions = vec![H256::from(1), H256::from(2)]; + + // when + indexer.set_poll_transactions(&poll_id, transactions.clone()); + assert!(indexer.poll_transactions(&poll_id).is_some()); + indexer.remove_poll(&poll_id); + + // then + assert!(indexer.poll_transactions(&poll_id).is_none()); + } + + #[test] + fn should_ignore_transactions_for_invalid_poll_id() { + // given + let mut indexer = PollManager::<()>::new(); + let transactions = vec![H256::from(1), H256::from(2)]; + + // when + indexer.set_poll_transactions(&5, transactions.clone()); + + // then + assert!(indexer.poll_transactions(&5).is_none()); + } } From c37370a8a777f503307d341381cd00f3fc27ff08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 16:00:55 +0100 Subject: [PATCH 475/753] PendingTransaction filter. --- miner/src/miner.rs | 8 ++++++++ miner/src/transaction_queue.rs | 26 ++++++++++++++++++++++++ parity/main.rs | 2 +- rpc/src/v1/helpers/poll_manager.rs | 32 +++++++++++++++++------------- rpc/src/v1/impls/eth.rs | 32 ++++++++++++++++++++++++------ 5 files changed, 79 insertions(+), 21 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 8e93defcf..85dbc6bbc 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -34,6 +34,9 @@ pub trait MinerService { fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256; + /// Returns hashes of transactions currently in pending + fn pending_transactions_hashes(&self) -> Vec; + /// Removes all transactions from the queue and restart mining operation. fn clear_and_reset(&self, chain: &BlockChainClient); @@ -135,6 +138,11 @@ impl MinerService for Miner { transaction_queue.add_all(transactions, fetch_nonce) } + fn pending_transactions_hashes(&self) -> Vec { + let transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.pending_hashes() + } + fn prepare_sealing(&self, chain: &BlockChainClient) { let no_of_transactions = 128; let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index f64bd7318..4379531b2 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -431,6 +431,14 @@ impl TransactionQueue { .collect() } + /// Returns hashes of all transactions from current, ordered by priority. + pub fn pending_hashes(&self) -> Vec { + self.current.by_priority + .iter() + .map(|t| t.hash) + .collect() + } + /// Removes all elements (in any state) from the queue pub fn clear(&mut self) { self.current.clear(); @@ -693,6 +701,24 @@ mod test { assert_eq!(top.len(), 2); } + #[test] + fn should_return_pending_hashes() { + // given + let mut txq = TransactionQueue::new(); + + let (tx, tx2) = new_txs(U256::from(1)); + + // when + txq.add(tx.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); + + // then + let top = txq.pending_hashes(); + assert_eq!(top[0], tx.hash()); + assert_eq!(top[1], tx2.hash()); + assert_eq!(top.len(), 2); + } + #[test] fn should_put_transaction_to_futures_if_gap_detected() { // given diff --git a/parity/main.rs b/parity/main.rs index c73f971d9..d83fe680d 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -209,7 +209,7 @@ fn setup_rpc_server(client: Arc, sync: Arc, miner: Arc, "net" => server.add_delegate(NetClient::new(&sync).to_delegate()), "eth" => { server.add_delegate(EthClient::new(&client, &sync, &miner).to_delegate()); - server.add_delegate(EthFilterClient::new(&client).to_delegate()); + server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); } _ => { die!("{}: Invalid API name to be enabled.", api); diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index 6c0862633..73b273a8f 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -102,15 +102,19 @@ impl PollManager where T: Timer { self.polls.get(id) } - pub fn set_poll_transactions(&mut self, id: &PollId, transactions: Vec) { + pub fn update_transactions(&mut self, id: &PollId, transactions: Vec) -> Option> { self.prune(); if self.polls.get(id).is_some() { - self.transactions_data.insert(*id, transactions); + self.transactions_data.insert(*id, transactions) + } else { + None } } + // Normal code always replaces transactions + #[cfg(test)] /// Returns last transactions hashes for given poll. - pub fn poll_transactions(&mut self, id: &PollId) -> Option<&Vec> { + pub fn transactions(&mut self, id: &PollId) -> Option<&Vec> { self.prune(); self.transactions_data.get(id) } @@ -175,14 +179,14 @@ mod tests { // given let mut indexer = PollManager::new(); let poll_id = indexer.create_poll(false, 20); - assert!(indexer.poll_transactions(&poll_id).is_none()); + assert!(indexer.transactions(&poll_id).is_none()); let transactions = vec![H256::from(1), H256::from(2)]; // when - indexer.set_poll_transactions(&poll_id, transactions.clone()); + indexer.update_transactions(&poll_id, transactions.clone()); // then - let txs = indexer.poll_transactions(&poll_id); + let txs = indexer.transactions(&poll_id); assert_eq!(txs.unwrap(), &transactions); } @@ -197,15 +201,15 @@ mod tests { let mut indexer = PollManager::new_with_timer(timer); let poll_id = indexer.create_poll(false, 20); let transactions = vec![H256::from(1), H256::from(2)]; - indexer.set_poll_transactions(&poll_id, transactions.clone()); - assert!(indexer.poll_transactions(&poll_id).is_some()); + indexer.update_transactions(&poll_id, transactions.clone()); + assert!(indexer.transactions(&poll_id).is_some()); // when *time.borrow_mut() = 75; indexer.prune(); // then - assert!(indexer.poll_transactions(&poll_id).is_none()); + assert!(indexer.transactions(&poll_id).is_none()); } @@ -217,12 +221,12 @@ mod tests { let transactions = vec![H256::from(1), H256::from(2)]; // when - indexer.set_poll_transactions(&poll_id, transactions.clone()); - assert!(indexer.poll_transactions(&poll_id).is_some()); + indexer.update_transactions(&poll_id, transactions.clone()); + assert!(indexer.transactions(&poll_id).is_some()); indexer.remove_poll(&poll_id); // then - assert!(indexer.poll_transactions(&poll_id).is_none()); + assert!(indexer.transactions(&poll_id).is_none()); } #[test] @@ -232,9 +236,9 @@ mod tests { let transactions = vec![H256::from(1), H256::from(2)]; // when - indexer.set_poll_transactions(&5, transactions.clone()); + indexer.update_transactions(&5, transactions.clone()); // then - assert!(indexer.poll_transactions(&5).is_none()); + assert!(indexer.transactions(&5).is_none()); } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a9ee389f8..5c7df574d 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Eth rpc implementation. -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::sync::{Arc, Weak, Mutex, RwLock}; use std::ops::Deref; use ethsync::{EthSync, SyncState}; @@ -264,15 +264,17 @@ impl Eth for EthClient { /// Eth filter rpc implementation. pub struct EthFilterClient { client: Weak, + miner: Weak, polls: Mutex>, } impl EthFilterClient { /// Creates new Eth filter client. - pub fn new(client: &Arc) -> Self { + pub fn new(client: &Arc, miner: &Arc) -> Self { EthFilterClient { client: Arc::downgrade(client), - polls: Mutex::new(PollManager::new()) + miner: Arc::downgrade(miner), + polls: Mutex::new(PollManager::new()), } } } @@ -302,7 +304,12 @@ impl EthFilter for EthFilterClient { match params { Params::None => { let mut polls = self.polls.lock().unwrap(); - let id = polls.create_poll(PollFilter::PendingTransaction, take_weak!(self.client).chain_info().best_block_number); + let best_block_number = take_weak!(self.client).chain_info().best_block_number; + let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); + + let id = polls.create_poll(PollFilter::PendingTransaction, best_block_number); + polls.update_transactions(&id, pending_transactions); + to_value(&U256::from(id)) }, _ => Err(Error::invalid_params()) @@ -330,8 +337,21 @@ impl EthFilter for EthFilterClient { to_value(&hashes) }, PollFilter::PendingTransaction => { - // TODO: fix implementation once TransactionQueue is merged - to_value(&vec![] as &Vec) + let poll_id = index.value(); + let mut polls = self.polls.lock().unwrap(); + + let current_hashes = take_weak!(self.miner).pending_transactions_hashes(); + let previous_hashes = polls.update_transactions(&poll_id, current_hashes.clone()).unwrap(); + polls.update_poll(&poll_id, client.chain_info().best_block_number); + + // calculate diff + let previous_hashes_set = previous_hashes.into_iter().collect::>(); + let diff = current_hashes + .into_iter() + .filter(|hash| previous_hashes_set.contains(&hash)) + .collect::>(); + + to_value(&diff) }, PollFilter::Logs(mut filter) => { filter.from_block = BlockId::Number(info.block_number); From 094ae4e9f9a77708c15751afa17c4835e1fb16a0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 19:15:10 +0400 Subject: [PATCH 476/753] personal is back to the master ver --- rpc/src/v1/impls/personal.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index a2788b9d9..48e1b1c6a 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -18,27 +18,28 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; use v1::traits::Personal; +use util::keys::store::*; use util::Address; -use ethcore::client::Client; +use std::sync::RwLock; /// Account management (personal) rpc implementation. pub struct PersonalClient { - client: Weak, + secret_store: Weak>, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(client: &Arc) -> Self { + pub fn new(store: &Arc>) -> Self { PersonalClient { - client: Arc::downgrade(client), + secret_store: Arc::downgrade(store), } } } impl Personal for PersonalClient { fn accounts(&self, _: Params) -> Result { - let client = take_weak!(self.client); - let store = client.secret_store().read().unwrap(); + let store_wk = take_weak!(self.secret_store); + let store = store_wk.read().unwrap(); match store.accounts() { Ok(account_list) => { Ok(Value::Array(account_list.iter() @@ -53,8 +54,8 @@ impl Personal for PersonalClient { fn new_account(&self, params: Params) -> Result { from_params::<(String, )>(params).and_then( |(pass, )| { - let client = take_weak!(self.client); - let mut store = client.secret_store().write().unwrap(); + let store_wk = take_weak!(self.secret_store); + let mut store = store_wk.write().unwrap(); match store.new_account(&pass) { Ok(address) => Ok(Value::String(format!("{:?}", address))), Err(_) => Err(Error::internal_error()) @@ -66,8 +67,8 @@ impl Personal for PersonalClient { fn unlock_account(&self, params: Params) -> Result { from_params::<(Address, String, u64)>(params).and_then( |(account, account_pass, _)|{ - let client = take_weak!(self.client); - let store = client.secret_store().read().unwrap(); + let store_wk = take_weak!(self.secret_store); + let store = store_wk.read().unwrap(); match store.unlock_account(&account, &account_pass) { Ok(_) => Ok(Value::Bool(true)), Err(_) => Ok(Value::Bool(false)), From 0eaf0a8db1827a005f5ae920736136ef33f4d70f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 16:40:15 +0100 Subject: [PATCH 477/753] Updating hook. --- hook.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hook.sh b/hook.sh index 113bf1838..25877868a 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,3 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer --features dev-clippy" > ./.git/hooks/pre-push +echo "#!/bin/sh\ncargo build --features dev-clippy && cargo test --no-run -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer --features dev-clippy" > ./.git/hooks/pre-push chmod +x ./.git/hooks/pre-push From c951dee7668e4d6ef5164230bdc1d41b77e4254e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 10 Mar 2016 17:09:34 +0100 Subject: [PATCH 478/753] --archive is default. --pruning is option. --- parity/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 68d45bc04..69650270a 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -79,7 +79,7 @@ Protocol Options: or olympic, frontier, homestead, mainnet, morden, or testnet [default: homestead]. --testnet Equivalent to --chain testnet (geth-compatible). --networkid INDEX Override the network identifier from the chain we are on. - --archive Client should not prune the state/storage trie. + --pruning Client should prune the state/storage trie. -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --identity NAME Specify your node's name. @@ -140,7 +140,7 @@ struct Args { flag_identity: String, flag_cache: Option, flag_keys_path: String, - flag_archive: bool, + flag_pruning: bool, flag_no_bootstrap: bool, flag_listen_address: String, flag_public_address: Option, @@ -402,7 +402,7 @@ impl Configuration { client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; } } - client_config.prefer_journal = !self.args.flag_archive; + client_config.prefer_journal = self.args.flag_pruning; client_config.name = self.args.flag_identity.clone(); client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); From 5571503c224b5d1b185243d7f5e6f1f1bc3a6856 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 20:18:01 +0400 Subject: [PATCH 479/753] traitified secret store --- rpc/src/v1/impls/eth.rs | 16 +++++++++------- util/src/keys/store.rs | 22 ++++++++++++++++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 4a8461c45..97d248ef6 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -30,20 +30,23 @@ use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; use v1::helpers::{PollFilter, PollManager}; +use util::keys::store::AccountProvider; /// Eth rpc implementation. -pub struct EthClient where C: BlockChainClient, S: SyncStatusProvider { +pub struct EthClient where C: BlockChainClient, S: SyncStatusProvider, A: AccountProvider { client: Weak, sync: Weak, + accounts: Weak, hashrates: RwLock>, } -impl EthClient where C: BlockChainClient, S: SyncStatusProvider { +impl EthClient where C: BlockChainClient, S: SyncStatusProvider, A: AccountProvider { /// Creates new EthClient. - pub fn new(client: &Arc, sync: &Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc, accounts: &Arc) -> Self { EthClient { client: Arc::downgrade(client), sync: Arc::downgrade(sync), + accounts: Arc::downgrade(accounts), hashrates: RwLock::new(HashMap::new()), } } @@ -94,7 +97,7 @@ impl EthClient where C: BlockChainClient, S: SyncStatusProvider { } } -impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncStatusProvider + 'static { +impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncStatusProvider + 'static, A: AccountProvider + 'static { fn protocol_version(&self, params: Params) -> Result { match params { Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)), @@ -256,9 +259,8 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncS fn send_transaction(&self, params: Params) -> Result { from_params::<(TransactionRequest, )>(params) .and_then(|(transaction_request, )| { - let client = take_weak!(self.client); - let store = client.secret_store().read().unwrap(); - match store.account_secret(&transaction_request.from) { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&transaction_request.from) { Ok(secret) => { let sync = take_weak!(self.sync); let (transaction, _) = transaction_request.to_eth(); diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index dcc165259..9ea00cbba 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -78,6 +78,18 @@ struct AccountUnlock { expires: DateTime, } +/// Basic account management trait +pub trait AccountProvider : Send + Sync { + /// Unlocks account with the password provided + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError>; + /// Creates account + fn new_account(&mut self, pass: &str) -> Result; + /// Returns secret for unlocked account + fn account_secret(&self, account: &Address) -> Result; + /// Returns secret for unlocked account + fn sign(&self, account: &Address, message: &H256) -> Result; +} + impl SecretStore { /// new instance of Secret Store in default home directory pub fn new() -> SecretStore { @@ -144,9 +156,11 @@ impl SecretStore { unlocks: RwLock::new(HashMap::new()), } } +} +impl AccountProvider for SecretStore { /// Unlocks account for use - pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier)); let secret = try!(self.get(&secret_id, pass)); { @@ -160,7 +174,7 @@ impl SecretStore { } /// Creates new account - pub fn new_account(&mut self, pass: &str) -> Result { + fn new_account(&mut self, pass: &str) -> Result { let secret = H256::random(); let key_id = H128::random(); self.insert(key_id.clone(), secret, pass); @@ -173,7 +187,7 @@ impl SecretStore { } /// Signs message with unlocked account - pub fn sign(&self, account: &Address, message: &H256) -> Result { + fn sign(&self, account: &Address, message: &H256) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); match crypto::KeyPair::from_secret(unlock.secret) { @@ -186,7 +200,7 @@ impl SecretStore { } /// Returns secret for unlocked account - pub fn account_secret(&self, account: &Address) -> Result { + fn account_secret(&self, account: &Address) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); Ok(unlock.secret as crypto::Secret) From 25a63611f856ab0896b114b6388461c174bf9905 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 20:32:17 +0400 Subject: [PATCH 480/753] extend sync status interface to sync provider --- parity/main.rs | 2 +- rpc/src/v1/impls/eth.rs | 8 ++++---- rpc/src/v1/impls/net.rs | 8 ++++---- sync/src/lib.rs | 20 +++++++++++--------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 8814da44b..d2b9b3567 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -49,7 +49,7 @@ use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; -use ethsync::{EthSync, SyncConfig, SyncStatusProvider}; +use ethsync::{EthSync, SyncConfig, SyncProvider}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 91bd0cce3..a067b48fb 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -17,7 +17,7 @@ //! Eth rpc implementation. use std::collections::HashMap; use std::sync::{Arc, Weak, Mutex, RwLock}; -use ethsync::{SyncStatusProvider, SyncState}; +use ethsync::{SyncProvider, SyncState}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; @@ -32,13 +32,13 @@ use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncIn use v1::helpers::{PollFilter, PollManager}; /// Eth rpc implementation. -pub struct EthClient where C: BlockChainClient, S: SyncStatusProvider { +pub struct EthClient where C: BlockChainClient, S: SyncProvider { client: Weak, sync: Weak, hashrates: RwLock>, } -impl EthClient where C: BlockChainClient, S: SyncStatusProvider { +impl EthClient where C: BlockChainClient, S: SyncProvider { /// Creates new EthClient. pub fn new(client: &Arc, sync: &Arc) -> Self { EthClient { @@ -94,7 +94,7 @@ impl EthClient where C: BlockChainClient, S: SyncStatusProvider { } } -impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncStatusProvider + 'static { +impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncProvider + 'static { fn protocol_version(&self, params: Params) -> Result { match params { Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)), diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index a686ed66f..5e67bf252 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -17,15 +17,15 @@ //! Net rpc implementation. use std::sync::{Arc, Weak}; use jsonrpc_core::*; -use ethsync::SyncStatusProvider; +use ethsync::SyncProvider; use v1::traits::Net; /// Net rpc implementation. -pub struct NetClient where S: SyncStatusProvider { +pub struct NetClient where S: SyncProvider { sync: Weak } -impl NetClient where S: SyncStatusProvider { +impl NetClient where S: SyncProvider { /// Creates new NetClient. pub fn new(sync: &Arc) -> Self { NetClient { @@ -34,7 +34,7 @@ impl NetClient where S: SyncStatusProvider { } } -impl Net for NetClient where S: SyncStatusProvider + 'static { +impl Net for NetClient where S: SyncProvider + 'static { fn version(&self, _: Params) -> Result { Ok(Value::U64(take_weak!(self.sync).status().protocol_version as u64)) } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 5a0ba79c5..3b79e5614 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -95,9 +95,11 @@ impl Default for SyncConfig { } /// Current sync status -pub trait SyncStatusProvider: Send + Sync { +pub trait SyncProvider: Send + Sync { /// Get sync status fn status(&self) -> SyncStatus; + /// Insert transaction in the sync transaction queue + fn insert_transaction(&self, transaction: ethcore::transaction::SignedTransaction); } /// Ethereum network protocol handler @@ -130,9 +132,16 @@ impl EthSync { pub fn restart(&mut self, io: &mut NetworkContext) { self.sync.write().unwrap().restart(&mut NetSyncIo::new(io, self.chain.deref())); } +} + +impl SyncProvider for EthSync { + /// Get sync status + fn status(&self) -> SyncStatus { + self.sync.read().unwrap().status() + } /// Insert transaction in transaction queue - pub fn insert_transaction(&self, transaction: ethcore::transaction::SignedTransaction) { + fn insert_transaction(&self, transaction: ethcore::transaction::SignedTransaction) { use util::numbers::*; let nonce_fn = |a: &Address| self.chain.state().nonce(a) + U256::one(); @@ -141,13 +150,6 @@ impl EthSync { } } -impl SyncStatusProvider for EthSync { - /// Get sync status - fn status(&self) -> SyncStatus { - self.sync.read().unwrap().status() - } -} - impl NetworkProtocolHandler for EthSync { fn initialize(&self, io: &NetworkContext) { io.register_timer(0, 1000).expect("Error registering sync timer"); From 84a48142defadd8b48654299c5d4d532f992261d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 10 Mar 2016 19:50:04 +0100 Subject: [PATCH 481/753] Add more geth options. --- parity/main.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 68d45bc04..cced0ed0f 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -70,9 +70,9 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] + parity daemon [options] parity account (new | list) - parity [options] [ --no-bootstrap | ... ] + parity [options] Protocol Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file @@ -85,13 +85,13 @@ Protocol Options: --identity NAME Specify your node's name. Networking Options: - --no-bootstrap Don't bother trying to connect to any nodes initially. - --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. - --public-address URL Specify the IP/port on which peers may connect. - --address URL Equivalent to --listen-address URL --public-address URL. - --peers NUM Try to maintain that many peers [default: 25]. + --no-bootstrap Don't bother trying to connect to standard bootnodes. + --bootnodes NODES Specify additional comma-separated bootnodes. --no-discovery Disable new peer discovery. - --no-upnp Disable trying to figure out the correct public adderss over UPnP. + --peers NUM Try to maintain that many peers [default: 25]. + --port PORT Override the port for the node to listen on, supercedes --address. + --nat METHOD Specify method to use for determining public address. Must be one of: any, none, + upnp, extip:(IP) [default: upnp]. --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. API and Console Options: @@ -101,16 +101,11 @@ API and Console Options: --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. --jsonrpc-apis APIS Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited list of API name. Possible name are web3, eth and net. [default: web3,eth,net]. - --rpc Equivalent to --jsonrpc (geth-compatible). - --rpcaddr HOST Equivalent to --jsonrpc-addr HOST (geth-compatible). - --rpcport PORT Equivalent to --jsonrpc-port PORT (geth-compatible). - --rpcapi APIS Equivalent to --jsonrpc-apis APIS (geth-compatible). - --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). Sealing/Mining Options: --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. - --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. + --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. Memory Footprint Options: --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. @@ -119,6 +114,18 @@ Memory Footprint Options: --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with other cache options (geth-compatible). +Geth-Compatibility Options + --rpc Equivalent to --jsonrpc. + --rpcaddr HOST Equivalent to --jsonrpc-addr HOST. + --rpcport PORT Equivalent to --jsonrpc-port PORT. + --rpcapi APIS Equivalent to --jsonrpc-apis APIS. + --rpccorsdomain URL Equivalent to --jsonrpc-cors URL. + --maxpeers COUNT Equivalent to --peers COUNT. + --nodekey KEY Equivalent to --node-key KEY. + --nodiscover Equivalent to --no-discovery. + --etherbase ADDRESS Equivalent to --author ADDRESS. + --extradata STRING Equivalent to --extra-data STRING. + Miscellaneous Options: -l --logging LOGGING Specify the logging level. -v --version Show information about version. @@ -145,7 +152,7 @@ struct Args { flag_listen_address: String, flag_public_address: Option, flag_address: Option, - flag_peers: usize, + flag_maxpeers: usize, flag_no_discovery: bool, flag_no_upnp: bool, flag_node_key: Option, @@ -323,7 +330,7 @@ impl Configuration { ret.public_address = public; ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3())); ret.discovery_enabled = !self.args.flag_no_discovery; - ret.ideal_peers = self.args.flag_peers as u32; + ret.ideal_peers = self.args.flag_maxpeers as u32; let mut net_path = PathBuf::from(&self.path()); net_path.push("network"); ret.config_path = Some(net_path.to_str().unwrap().to_owned()); From a2dea3885b393da47dad0127f22773b7fcae00bc Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 23:09:45 +0400 Subject: [PATCH 482/753] refactoring to AccountService --- parity/main.rs | 10 ++----- rpc/src/v1/impls/personal.rs | 18 +++++------- util/src/keys/store.rs | 53 +++++++++++++++++++++++++++++++----- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 6d1c08162..b6ed5cba3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -196,7 +196,7 @@ fn setup_log(init: &Option) { } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, secret_store: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) -> Option> { +fn setup_rpc_server(client: Arc, sync: Arc, secret_store: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) -> Option> { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -416,11 +416,7 @@ impl Configuration { let sync = EthSync::register(service.network(), sync_config, client); // Secret Store - let secret_store = Arc::new(SecretStore::new()); - { - let import_ref = Arc::make_mut(&mut secret_store); - import_ref.try_import_existing(); - } + let account_service = Arc::new(AccountService::new()); // Setup rpc if self.args.flag_jsonrpc || self.args.flag_rpc { @@ -432,7 +428,7 @@ impl Configuration { let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - let server_handler = setup_rpc_server(service.client(), sync.clone(), secret_store.clone(), &url, cors, apis.split(",").collect()); + let server_handler = setup_rpc_server(service.client(), sync.clone(), account_service.clone(), &url, cors, apis.split(",").collect()); if let Some(handler) = server_handler { panic_handler.forward_from(handler.deref()); } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 48e1b1c6a..7b79ceae7 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -20,30 +20,28 @@ use jsonrpc_core::*; use v1::traits::Personal; use util::keys::store::*; use util::Address; -use std::sync::RwLock; /// Account management (personal) rpc implementation. pub struct PersonalClient { - secret_store: Weak>, + accounts: Weak, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(store: &Arc>) -> Self { + pub fn new(store: &Arc) -> Self { PersonalClient { - secret_store: Arc::downgrade(store), + accounts: Arc::downgrade(store), } } } impl Personal for PersonalClient { fn accounts(&self, _: Params) -> Result { - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let store = take_weak!(self.accounts); match store.accounts() { Ok(account_list) => { Ok(Value::Array(account_list.iter() - .map(|&(account, _)| Value::String(format!("{:?}", account))) + .map(|&account| Value::String(format!("{:?}", account))) .collect::>()) ) } @@ -54,8 +52,7 @@ impl Personal for PersonalClient { fn new_account(&self, params: Params) -> Result { from_params::<(String, )>(params).and_then( |(pass, )| { - let store_wk = take_weak!(self.secret_store); - let mut store = store_wk.write().unwrap(); + let store = take_weak!(self.accounts); match store.new_account(&pass) { Ok(address) => Ok(Value::String(format!("{:?}", address))), Err(_) => Err(Error::internal_error()) @@ -67,8 +64,7 @@ impl Personal for PersonalClient { fn unlock_account(&self, params: Params) -> Result { from_params::<(Address, String, u64)>(params).and_then( |(account, account_pass, _)|{ - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let store = take_weak!(self.accounts); match store.unlock_account(&account, &account_pass) { Ok(_) => Ok(Value::Bool(true)), Err(_) => Ok(Value::Bool(false)), diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 9ea00cbba..ea97cc80e 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -80,16 +80,57 @@ struct AccountUnlock { /// Basic account management trait pub trait AccountProvider : Send + Sync { + /// Lists all accounts + fn accounts(&self) -> Result, ::std::io::Error>; /// Unlocks account with the password provided fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError>; /// Creates account - fn new_account(&mut self, pass: &str) -> Result; + fn new_account(&self, pass: &str) -> Result; /// Returns secret for unlocked account fn account_secret(&self, account: &Address) -> Result; /// Returns secret for unlocked account fn sign(&self, account: &Address, message: &H256) -> Result; } +/// Thread-safe accounts management +pub struct AccountService { + secret_store: RwLock, +} + +impl AccountProvider for AccountService { + /// Lists all accounts + fn accounts(&self) -> Result, ::std::io::Error> { + Ok(try!(self.secret_store.read().unwrap().accounts()).iter().map(|&(addr, _)| addr).collect::>()) + } + /// Unlocks account with the password provided + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + self.secret_store.read().unwrap().unlock_account(account, pass) + } + /// Creates account + fn new_account(&self, pass: &str) -> Result { + self.secret_store.write().unwrap().new_account(pass) + } + /// Returns secret for unlocked account + fn account_secret(&self, account: &Address) -> Result { + self.secret_store.read().unwrap().account_secret(account) + } + /// Returns secret for unlocked account + fn sign(&self, account: &Address, message: &H256) -> Result { + self.secret_store.read().unwrap().sign(account, message) + } +} + +impl AccountService { + /// New account service with the default location + pub fn new() -> AccountService { + let secret_store = RwLock::new(SecretStore::new()); + secret_store.write().unwrap().try_import_existing(); + AccountService { + secret_store: secret_store + } + } +} + impl SecretStore { /// new instance of Secret Store in default home directory pub fn new() -> SecretStore { @@ -156,11 +197,9 @@ impl SecretStore { unlocks: RwLock::new(HashMap::new()), } } -} -impl AccountProvider for SecretStore { /// Unlocks account for use - fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier)); let secret = try!(self.get(&secret_id, pass)); { @@ -174,7 +213,7 @@ impl AccountProvider for SecretStore { } /// Creates new account - fn new_account(&mut self, pass: &str) -> Result { + pub fn new_account(&mut self, pass: &str) -> Result { let secret = H256::random(); let key_id = H128::random(); self.insert(key_id.clone(), secret, pass); @@ -187,7 +226,7 @@ impl AccountProvider for SecretStore { } /// Signs message with unlocked account - fn sign(&self, account: &Address, message: &H256) -> Result { + pub fn sign(&self, account: &Address, message: &H256) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); match crypto::KeyPair::from_secret(unlock.secret) { @@ -200,7 +239,7 @@ impl AccountProvider for SecretStore { } /// Returns secret for unlocked account - fn account_secret(&self, account: &Address) -> Result { + pub fn account_secret(&self, account: &Address) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); Ok(unlock.secret as crypto::Secret) From c5c8851b5097e27ccadc43b579dd8f605b9c9733 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 10 Mar 2016 20:27:50 +0100 Subject: [PATCH 483/753] moved TestBlockChainClient to ethcore --- ethcore/src/client/mod.rs | 2 + ethcore/src/client/test_client.rs | 322 ++++++++++++++++++++++++++++++ ethcore/src/lib.rs | 2 +- sync/src/tests/chain.rs | 2 +- sync/src/tests/helpers.rs | 292 +-------------------------- 5 files changed, 327 insertions(+), 293 deletions(-) create mode 100644 ethcore/src/client/test_client.rs diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 0daa17553..58a21f151 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -19,10 +19,12 @@ mod client; mod config; mod ids; +mod test_client; pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; pub use self::ids::{BlockId, TransactionId}; +pub use self::test_client::{TestBlockChainClient, EachBlockWith}; use util::bytes::Bytes; use util::hash::{Address, H256, H2048}; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs new file mode 100644 index 000000000..4ca30dcd5 --- /dev/null +++ b/ethcore/src/client/test_client.rs @@ -0,0 +1,322 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//use std::mem; +//use std::ops::{Deref, DerefMut}; +//use std::collections::HashMap; +//use rustc_serialize::hex::FromHex; +//use util::rlp; +//use util::rlp::*; +//use util::bytes::Bytes; +//use util::hash::{FixedHash, Address, H256, H2048}; +//use util::numbers::{Uint, U256}; +//use util::crypto::KeyPair; +//use util::sha3::Hashable; +use util::*; +//use std::sync::RwLock; +use transaction::{Transaction, LocalizedTransaction, Action}; +use blockchain::TreeRoute; +use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId}; +use header::{Header as BlockHeader, BlockNumber}; +use filter::Filter; +use log_entry::LocalizedLogEntry; +use receipt::Receipt; +use error::ImportResult; +use block_queue::BlockQueueInfo; + +pub struct TestBlockChainClient { + pub blocks: RwLock>, + pub numbers: RwLock>, + pub genesis_hash: H256, + pub last_hash: RwLock, + pub difficulty: RwLock, +} + +#[derive(Clone)] +pub enum EachBlockWith { + Nothing, + Uncle, + Transaction, + UncleAndTransaction +} + +impl TestBlockChainClient { + pub fn new() -> TestBlockChainClient { + + let mut client = TestBlockChainClient { + blocks: RwLock::new(HashMap::new()), + numbers: RwLock::new(HashMap::new()), + genesis_hash: H256::new(), + last_hash: RwLock::new(H256::new()), + difficulty: RwLock::new(From::from(0)), + }; + client.add_blocks(1, EachBlockWith::Nothing); // add genesis block + client.genesis_hash = client.last_hash.read().unwrap().clone(); + client + } + + pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { + let len = self.numbers.read().unwrap().len(); + for n in len..(len + count) { + let mut header = BlockHeader::new(); + header.difficulty = From::from(n); + header.parent_hash = self.last_hash.read().unwrap().clone(); + header.number = n as BlockNumber; + let uncles = match with { + EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { + let mut uncles = RlpStream::new_list(1); + let mut uncle_header = BlockHeader::new(); + uncle_header.difficulty = From::from(n); + uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); + uncle_header.number = n as BlockNumber; + uncles.append(&uncle_header); + header.uncles_hash = uncles.as_raw().sha3(); + uncles + }, + _ => RlpStream::new_list(0) + }; + let txs = match with { + EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { + let mut txs = RlpStream::new_list(1); + let keypair = KeyPair::create().unwrap(); + let tx = Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero() + }; + let signed_tx = tx.sign(&keypair.secret()); + txs.append(&signed_tx); + txs.out() + }, + _ => rlp::NULL_RLP.to_vec() + }; + + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&txs, 1); + rlp.append_raw(uncles.as_raw(), 1); + self.import_block(rlp.as_raw().to_vec()).unwrap(); + } + } + + pub fn corrupt_block(&mut self, n: BlockNumber) { + let hash = self.block_hash(BlockId::Number(n)).unwrap(); + let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); + header.parent_hash = H256::new(); + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&rlp::NULL_RLP, 1); + rlp.append_raw(&rlp::NULL_RLP, 1); + self.blocks.write().unwrap().insert(hash, rlp.out()); + } + + pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { + let blocks_read = self.numbers.read().unwrap(); + let index = blocks_read.len() - delta; + blocks_read[&index].clone() + } + + fn block_hash(&self, id: BlockId) -> Option { + match id { + BlockId::Hash(hash) => Some(hash), + BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), + BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), + BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() + } + } +} + +impl BlockChainClient for TestBlockChainClient { + fn block_total_difficulty(&self, _id: BlockId) -> Option { + Some(U256::zero()) + } + + fn block_hash(&self, _id: BlockId) -> Option { + unimplemented!(); + } + + fn nonce(&self, _address: &Address) -> U256 { + U256::zero() + } + + fn code(&self, _address: &Address) -> Option { + unimplemented!(); + } + + fn transaction(&self, _id: TransactionId) -> Option { + unimplemented!(); + } + + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { + unimplemented!(); + } + + fn logs(&self, _filter: Filter) -> Vec { + unimplemented!(); + } + + fn block_header(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) + } + + fn block_body(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { + let mut stream = RlpStream::new_list(2); + stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); + stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); + stream.out() + })) + } + + fn block(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) + } + + fn block_status(&self, id: BlockId) -> BlockStatus { + match id { + BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, + BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, + _ => BlockStatus::Unknown + } + } + + // works only if blocks are one after another 1 -> 2 -> 3 + fn tree_route(&self, from: &H256, to: &H256) -> Option { + Some(TreeRoute { + ancestor: H256::new(), + index: 0, + blocks: { + let numbers_read = self.numbers.read().unwrap(); + let mut adding = false; + + let mut blocks = Vec::new(); + for (_, hash) in numbers_read.iter().sort_by(|tuple1, tuple2| tuple1.0.cmp(tuple2.0)) { + if hash == to { + if adding { + blocks.push(hash.clone()); + } + adding = false; + break; + } + if hash == from { + adding = true; + } + if adding { + blocks.push(hash.clone()); + } + } + if adding { Vec::new() } else { blocks } + } + }) + } + + // TODO: returns just hashes instead of node state rlp(?) + fn state_data(&self, hash: &H256) -> Option { + // starts with 'f' ? + if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { + let mut rlp = RlpStream::new(); + rlp.append(&hash.clone()); + return Some(rlp.out()); + } + None + } + + fn block_receipts(&self, hash: &H256) -> Option { + // starts with 'f' ? + if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { + let receipt = Receipt::new( + H256::zero(), + U256::zero(), + vec![]); + let mut rlp = RlpStream::new(); + rlp.append(&receipt); + return Some(rlp.out()); + } + None + } + + fn import_block(&self, b: Bytes) -> ImportResult { + let header = Rlp::new(&b).val_at::(0); + let h = header.hash(); + let number: usize = header.number as usize; + if number > self.blocks.read().unwrap().len() { + panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); + } + if number > 0 { + match self.blocks.read().unwrap().get(&header.parent_hash) { + Some(parent) => { + let parent = Rlp::new(parent).val_at::(0); + if parent.number != (header.number - 1) { + panic!("Unexpected block parent"); + } + }, + None => { + panic!("Unknown block parent {:?} for block {}", header.parent_hash, number); + } + } + } + let len = self.numbers.read().unwrap().len(); + if number == len { + { + let mut difficulty = self.difficulty.write().unwrap(); + *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; + } + mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); + self.blocks.write().unwrap().insert(h.clone(), b); + self.numbers.write().unwrap().insert(number, h.clone()); + let mut parent_hash = header.parent_hash; + if number > 0 { + let mut n = number - 1; + while n > 0 && self.numbers.read().unwrap()[&n] != parent_hash { + *self.numbers.write().unwrap().get_mut(&n).unwrap() = parent_hash.clone(); + n -= 1; + parent_hash = Rlp::new(&self.blocks.read().unwrap()[&parent_hash]).val_at::(0).parent_hash; + } + } + } + else { + self.blocks.write().unwrap().insert(h.clone(), b.to_vec()); + } + Ok(h) + } + + fn queue_info(&self) -> BlockQueueInfo { + BlockQueueInfo { + verified_queue_size: 0, + unverified_queue_size: 0, + verifying_queue_size: 0, + max_queue_size: 0, + max_mem_use: 0, + mem_used: 0, + } + } + + fn clear_queue(&self) { + } + + fn chain_info(&self) -> BlockChainInfo { + BlockChainInfo { + total_difficulty: *self.difficulty.read().unwrap(), + pending_total_difficulty: *self.difficulty.read().unwrap(), + genesis_hash: self.genesis_hash.clone(), + best_block_hash: self.last_hash.read().unwrap().clone(), + best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, + } + } +} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 469364eb3..0ff5c1903 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -86,6 +86,7 @@ extern crate crossbeam; #[cfg(feature = "jit" )] extern crate evmjit; pub mod block; +pub mod block_queue; pub mod client; pub mod error; pub mod ethereum; @@ -119,7 +120,6 @@ mod substate; mod executive; mod externalities; mod verification; -mod block_queue; mod blockchain; #[cfg(test)] diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 855aa79a6..eebbdb164 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockId}; +use ethcore::client::{BlockChainClient, BlockId, EachBlockWith}; use io::SyncIo; use chain::{SyncState}; use super::helpers::*; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index d01dba0b2..ca4ae5158 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -15,300 +15,10 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId, BlockQueueInfo}; -use ethcore::header::{Header as BlockHeader, BlockNumber}; -use ethcore::error::*; +use ethcore::client::{TestBlockChainClient, BlockChainClient}; use io::SyncIo; use chain::ChainSync; use ::SyncConfig; -use ethcore::receipt::Receipt; -use ethcore::transaction::{LocalizedTransaction, Transaction, Action}; -use ethcore::filter::Filter; -use ethcore::log_entry::LocalizedLogEntry; - -pub struct TestBlockChainClient { - pub blocks: RwLock>, - pub numbers: RwLock>, - pub genesis_hash: H256, - pub last_hash: RwLock, - pub difficulty: RwLock, -} - -#[derive(Clone)] -pub enum EachBlockWith { - Nothing, - Uncle, - Transaction, - UncleAndTransaction -} - -impl TestBlockChainClient { - pub fn new() -> TestBlockChainClient { - - let mut client = TestBlockChainClient { - blocks: RwLock::new(HashMap::new()), - numbers: RwLock::new(HashMap::new()), - genesis_hash: H256::new(), - last_hash: RwLock::new(H256::new()), - difficulty: RwLock::new(From::from(0)), - }; - client.add_blocks(1, EachBlockWith::Nothing); // add genesis block - client.genesis_hash = client.last_hash.read().unwrap().clone(); - client - } - - pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { - let len = self.numbers.read().unwrap().len(); - for n in len..(len + count) { - let mut header = BlockHeader::new(); - header.difficulty = From::from(n); - header.parent_hash = self.last_hash.read().unwrap().clone(); - header.number = n as BlockNumber; - let uncles = match with { - EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { - let mut uncles = RlpStream::new_list(1); - let mut uncle_header = BlockHeader::new(); - uncle_header.difficulty = From::from(n); - uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); - uncle_header.number = n as BlockNumber; - uncles.append(&uncle_header); - header.uncles_hash = uncles.as_raw().sha3(); - uncles - }, - _ => RlpStream::new_list(0) - }; - let txs = match with { - EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { - let mut txs = RlpStream::new_list(1); - let keypair = KeyPair::create().unwrap(); - let tx = Transaction { - action: Action::Create, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: U256::from(100_000), - gas_price: U256::one(), - nonce: U256::zero() - }; - let signed_tx = tx.sign(&keypair.secret()); - txs.append(&signed_tx); - txs.out() - }, - _ => rlp::NULL_RLP.to_vec() - }; - - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&txs, 1); - rlp.append_raw(uncles.as_raw(), 1); - self.import_block(rlp.as_raw().to_vec()).unwrap(); - } - } - - pub fn corrupt_block(&mut self, n: BlockNumber) { - let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); - header.parent_hash = H256::new(); - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&rlp::NULL_RLP, 1); - rlp.append_raw(&rlp::NULL_RLP, 1); - self.blocks.write().unwrap().insert(hash, rlp.out()); - } - - pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { - let blocks_read = self.numbers.read().unwrap(); - let index = blocks_read.len() - delta; - blocks_read[&index].clone() - } - - fn block_hash(&self, id: BlockId) -> Option { - match id { - BlockId::Hash(hash) => Some(hash), - BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), - BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), - BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() - } - } -} - -impl BlockChainClient for TestBlockChainClient { - fn block_total_difficulty(&self, _id: BlockId) -> Option { - Some(U256::zero()) - } - - fn block_hash(&self, _id: BlockId) -> Option { - unimplemented!(); - } - - fn nonce(&self, _address: &Address) -> U256 { - U256::zero() - } - - fn code(&self, _address: &Address) -> Option { - unimplemented!(); - } - - fn transaction(&self, _id: TransactionId) -> Option { - unimplemented!(); - } - - fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { - unimplemented!(); - } - - fn logs(&self, _filter: Filter) -> Vec { - unimplemented!(); - } - - fn block_header(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) - } - - fn block_body(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { - let mut stream = RlpStream::new_list(2); - stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); - stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); - stream.out() - })) - } - - fn block(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) - } - - fn block_status(&self, id: BlockId) -> BlockStatus { - match id { - BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, - BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, - _ => BlockStatus::Unknown - } - } - - // works only if blocks are one after another 1 -> 2 -> 3 - fn tree_route(&self, from: &H256, to: &H256) -> Option { - Some(TreeRoute { - ancestor: H256::new(), - index: 0, - blocks: { - let numbers_read = self.numbers.read().unwrap(); - let mut adding = false; - - let mut blocks = Vec::new(); - for (_, hash) in numbers_read.iter().sort_by(|tuple1, tuple2| tuple1.0.cmp(tuple2.0)) { - if hash == to { - if adding { - blocks.push(hash.clone()); - } - adding = false; - break; - } - if hash == from { - adding = true; - } - if adding { - blocks.push(hash.clone()); - } - } - if adding { Vec::new() } else { blocks } - } - }) - } - - // TODO: returns just hashes instead of node state rlp(?) - fn state_data(&self, hash: &H256) -> Option { - // starts with 'f' ? - if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { - let mut rlp = RlpStream::new(); - rlp.append(&hash.clone()); - return Some(rlp.out()); - } - None - } - - fn block_receipts(&self, hash: &H256) -> Option { - // starts with 'f' ? - if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { - let receipt = Receipt::new( - H256::zero(), - U256::zero(), - vec![]); - let mut rlp = RlpStream::new(); - rlp.append(&receipt); - return Some(rlp.out()); - } - None - } - - fn import_block(&self, b: Bytes) -> ImportResult { - let header = Rlp::new(&b).val_at::(0); - let h = header.hash(); - let number: usize = header.number as usize; - if number > self.blocks.read().unwrap().len() { - panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); - } - if number > 0 { - match self.blocks.read().unwrap().get(&header.parent_hash) { - Some(parent) => { - let parent = Rlp::new(parent).val_at::(0); - if parent.number != (header.number - 1) { - panic!("Unexpected block parent"); - } - }, - None => { - panic!("Unknown block parent {:?} for block {}", header.parent_hash, number); - } - } - } - let len = self.numbers.read().unwrap().len(); - if number == len { - { - let mut difficulty = self.difficulty.write().unwrap(); - *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; - } - mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); - self.blocks.write().unwrap().insert(h.clone(), b); - self.numbers.write().unwrap().insert(number, h.clone()); - let mut parent_hash = header.parent_hash; - if number > 0 { - let mut n = number - 1; - while n > 0 && self.numbers.read().unwrap()[&n] != parent_hash { - *self.numbers.write().unwrap().get_mut(&n).unwrap() = parent_hash.clone(); - n -= 1; - parent_hash = Rlp::new(&self.blocks.read().unwrap()[&parent_hash]).val_at::(0).parent_hash; - } - } - } - else { - self.blocks.write().unwrap().insert(h.clone(), b.to_vec()); - } - Ok(h) - } - - fn queue_info(&self) -> BlockQueueInfo { - BlockQueueInfo { - verified_queue_size: 0, - unverified_queue_size: 0, - verifying_queue_size: 0, - max_queue_size: 0, - max_mem_use: 0, - mem_used: 0, - } - } - - fn clear_queue(&self) { - } - - fn chain_info(&self) -> BlockChainInfo { - BlockChainInfo { - total_difficulty: *self.difficulty.read().unwrap(), - pending_total_difficulty: *self.difficulty.read().unwrap(), - genesis_hash: self.genesis_hash.clone(), - best_block_hash: self.last_hash.read().unwrap().clone(), - best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, - } - } -} pub struct TestIo<'p> { pub chain: &'p mut TestBlockChainClient, From 5f37f6edb442aa41097f7c014d2a0a08b20cb1f0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 10 Mar 2016 21:01:17 +0100 Subject: [PATCH 484/753] Correct cache update order --- ethcore/src/blockchain/blockchain.rs | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8e56cdc5f..4ebd111d9 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -452,7 +452,32 @@ impl BlockChain { let batch = DBTransaction::new(); batch.put(b"best", &update.info.hash).unwrap(); - // These cached values must be updated atomically + { + let mut write_details = self.block_details.write().unwrap(); + for (hash, details) in update.block_details.into_iter() { + batch.put_extras(&hash, &details); + self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); + write_details.insert(hash, details); + } + } + + { + let mut write_receipts = self.block_receipts.write().unwrap(); + for (hash, receipt) in &update.block_receipts { + batch.put_extras(hash, receipt); + write_receipts.remove(hash); + } + } + + { + let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); + for (bloom_hash, blocks_bloom) in &update.blocks_blooms { + batch.put_extras(bloom_hash, blocks_bloom); + write_blocks_blooms.remove(bloom_hash); + } + } + + // These cached values must be updated last and togeterh { let mut best_block = self.best_block.write().unwrap(); let mut write_hashes = self.block_hashes.write().unwrap(); @@ -481,31 +506,6 @@ impl BlockChain { } } - { - let mut write_details = self.block_details.write().unwrap(); - for (hash, details) in update.block_details.into_iter() { - batch.put_extras(&hash, &details); - self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); - write_details.insert(hash, details); - } - } - - { - let mut write_receipts = self.block_receipts.write().unwrap(); - for (hash, receipt) in &update.block_receipts { - batch.put_extras(hash, receipt); - write_receipts.remove(hash); - } - } - - { - let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); - for (bloom_hash, blocks_bloom) in &update.blocks_blooms { - batch.put_extras(bloom_hash, blocks_bloom); - write_blocks_blooms.remove(bloom_hash); - } - } - // update extras database self.extras_db.write(batch).unwrap(); } From 06a3abd01e0cd6f2435510c1133c34e87c48beff Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 10 Mar 2016 21:15:43 +0100 Subject: [PATCH 485/753] Removed unused return type --- util/src/journaldb.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 97ae077b2..4f2cdeb31 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -153,7 +153,7 @@ impl JournalDB { } /// Commit all recent insert operations. - pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result<(), UtilError> { let have_journal_overlay = self.journal_overlay.is_some(); if have_journal_overlay { self.commit_with_overlay(now, id, end) @@ -183,16 +183,16 @@ impl JournalDB { } /// Just commit the transaction overlay into the backing DB. - fn commit_without_overlay(&mut self) -> Result { + fn commit_without_overlay(&mut self) -> Result<(), UtilError> { let batch = DBTransaction::new(); - let ret = Self::batch_overlay_insertions(&mut self.transaction_overlay, &batch); + Self::batch_overlay_insertions(&mut self.transaction_overlay, &batch); try!(self.backing.write(batch)); - Ok(ret as u32) + Ok(()) } /// Commit all recent insert operations and historical removals from the old era /// to the backing database. - fn commit_with_overlay(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + fn commit_with_overlay(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result<(), UtilError> { // record new commit's details. trace!("commit: #{} ({}), end era: {:?}", now, id, end); let mut journal_overlay = self.journal_overlay.as_mut().unwrap().write().unwrap(); @@ -274,7 +274,7 @@ impl JournalDB { journal_overlay.journal.remove(&end_era); } try!(self.backing.write(batch)); - Ok(0 as u32) + Ok(()) } fn payload(&self, key: &H256) -> Option { From 29916edb91092d95a5a08c10075bea2bb7098a3f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 10 Mar 2016 21:36:45 +0100 Subject: [PATCH 486/753] More geth compatibility. --- parity/main.rs | 101 +++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index cced0ed0f..402017f3c 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -37,7 +37,7 @@ extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; -use std::net::{SocketAddr}; +use std::net::{SocketAddr, IpAddr}; use std::env; use std::process::exit; use std::path::PathBuf; @@ -77,21 +77,19 @@ Usage: Protocol Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, or testnet [default: homestead]. - --testnet Equivalent to --chain testnet (geth-compatible). - --networkid INDEX Override the network identifier from the chain we are on. - --archive Client should not prune the state/storage trie. - -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] + --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --identity NAME Specify your node's name. + --archive Client should not prune the state/storage trie. Networking Options: - --no-bootstrap Don't bother trying to connect to standard bootnodes. - --bootnodes NODES Specify additional comma-separated bootnodes. - --no-discovery Disable new peer discovery. + --port PORT Override the port on which the node should listen [default: 30303]. --peers NUM Try to maintain that many peers [default: 25]. - --port PORT Override the port for the node to listen on, supercedes --address. --nat METHOD Specify method to use for determining public address. Must be one of: any, none, - upnp, extip:(IP) [default: upnp]. + upnp, extip:(IP) [default: any]. + --bootnodes NODES Specify additional comma-separated bootnodes. + --no-bootstrap Don't bother trying to connect to standard bootnodes. + --no-discovery Disable new peer discovery. --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. API and Console Options: @@ -115,6 +113,9 @@ Memory Footprint Options: other cache options (geth-compatible). Geth-Compatibility Options + --datadir PATH Equivalent to --db-path PATH. + --testnet Equivalent to --chain testnet. + --networkid INDEX Override the network identifier from the chain we are on. --rpc Equivalent to --jsonrpc. --rpcaddr HOST Equivalent to --jsonrpc-addr HOST. --rpcport PORT Equivalent to --jsonrpc-port PORT. @@ -139,22 +140,18 @@ struct Args { cmd_new: bool, cmd_list: bool, arg_pid_file: String, - arg_enode: Vec, flag_chain: String, - flag_testnet: bool, - flag_datadir: String, - flag_networkid: Option, + flag_db_path: String, flag_identity: String, flag_cache: Option, flag_keys_path: String, flag_archive: bool, + flag_bootnodes: Option, flag_no_bootstrap: bool, - flag_listen_address: String, - flag_public_address: Option, - flag_address: Option, - flag_maxpeers: usize, + flag_port: u16, + flag_peers: usize, flag_no_discovery: bool, - flag_no_upnp: bool, + flag_nat: String, flag_node_key: Option, flag_cache_pref_size: usize, flag_cache_max_size: usize, @@ -164,15 +161,24 @@ struct Args { flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, + flag_logging: Option, + flag_version: bool, + // geth-compatibility... + flag_nodekey: Option, + flag_nodiscover: bool, + flag_maxpeers: Option, + flag_author: String, + flag_extra_data: Option, + flag_datadir: Option, + flag_extradata: Option, + flag_etherbase: Option, flag_rpc: bool, flag_rpcaddr: Option, flag_rpcport: Option, flag_rpccorsdomain: Option, flag_rpcapi: Option, - flag_logging: Option, - flag_version: bool, - flag_author: String, - flag_extra_data: Option, + flag_testnet: bool, + flag_networkid: Option, } fn setup_log(init: &Option) { @@ -252,15 +258,17 @@ impl Configuration { } fn path(&self) -> String { - self.args.flag_datadir.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + let d = self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path); + d.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } fn author(&self) -> Address { - Address::from_str(&self.args.flag_author).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) + let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author); + Address::from_str(d).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) } fn extra_data(&self) -> Bytes { - match self.args.flag_extra_data { + match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) { Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(), None => version_data(), Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); } @@ -292,45 +300,40 @@ impl Configuration { } fn init_nodes(&self, spec: &Spec) -> Vec { - if self.args.flag_no_bootstrap { Vec::new() } else { - match self.args.arg_enode.len() { - 0 => spec.nodes().clone(), - _ => self.args.arg_enode.iter().map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s))).collect(), - } + let mut r = if self.args.flag_no_bootstrap { Vec::new() } else { spec.nodes().clone() }; + if let Some(ref x) = self.args.flag_bootnodes { + r.extend(x.split(",").map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s)))); } + r } #[cfg_attr(all(nightly, feature="dev"), allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { - let mut listen_address = None; - let mut public_address = None; + let listen_address = Some(SocketAddr::new(IpAddr::from_str("127.0.0.1").unwrap(), self.args.flag_port)); + + let host = if self.args.flag_nat.starts_with("extip:") { + &self.args.flag_nat[6..] + } else { + "127.0.0.1" + }; + let public_address = Some(SocketAddr::new( + IpAddr::from_str(&host).unwrap_or_else(|_| die!("{}: Invalid host given with --net extip:", host)), + self.args.flag_port + )); - if let Some(ref a) = self.args.flag_address { - public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --address", a))); - listen_address = public_address; - } - if listen_address.is_none() { - listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --listen-address", self.args.flag_listen_address))); - } - if let Some(ref a) = self.args.flag_public_address { - if public_address.is_some() { - die!("Conflicting flags provided: --address and --public-address"); - } - public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --public-address", a))); - } (listen_address, public_address) } fn net_settings(&self, spec: &Spec) -> NetworkConfiguration { let mut ret = NetworkConfiguration::new(); - ret.nat_enabled = !self.args.flag_no_upnp; + ret.nat_enabled = self.args.flag_nat == "any" || self.args.flag_nat == "upnp"; ret.boot_nodes = self.init_nodes(spec); let (listen, public) = self.net_addresses(); ret.listen_address = listen; ret.public_address = public; ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3())); - ret.discovery_enabled = !self.args.flag_no_discovery; - ret.ideal_peers = self.args.flag_maxpeers as u32; + ret.discovery_enabled = !self.args.flag_no_discovery && !self.args.flag_nodiscover; + ret.ideal_peers = self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32; let mut net_path = PathBuf::from(&self.path()); net_path.push("network"); ret.config_path = Some(net_path.to_str().unwrap().to_owned()); From d9c462a3d3bd5a15b5c8dc6c8424b85b4179349c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 10:05:27 +0100 Subject: [PATCH 487/753] Use proper listen address. Tidyups. --- parity/main.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index d6c3516d0..732e94f02 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -302,25 +302,21 @@ impl Configuration { fn init_nodes(&self, spec: &Spec) -> Vec { let mut r = if self.args.flag_no_bootstrap { Vec::new() } else { spec.nodes().clone() }; if let Some(ref x) = self.args.flag_bootnodes { - r.extend(x.split(",").map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s)))); + r.extend(x.split(",").map(|s| Self::normalize_enode(s).unwrap_or_else(|| die!("{}: Invalid node address format given for a boot node.", s)))); } r } #[cfg_attr(all(nightly, feature="dev"), allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { - let listen_address = Some(SocketAddr::new(IpAddr::from_str("127.0.0.1").unwrap(), self.args.flag_port)); - - let host = if self.args.flag_nat.starts_with("extip:") { - &self.args.flag_nat[6..] + let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), self.args.flag_port)); + let public_address = if self.args.flag_nat.starts_with("extip:") { + let host = &self.args.flag_nat[6..]; + let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host)); + Some(SocketAddr::new(host, self.args.flag_port)) } else { - "127.0.0.1" + listen_address.clone() }; - let public_address = Some(SocketAddr::new( - IpAddr::from_str(&host).unwrap_or_else(|_| die!("{}: Invalid host given with --net extip:", host)), - self.args.flag_port - )); - (listen_address, public_address) } From 34a120e1270288ffafc3518f8a4fb681ee5cfdf2 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 10:17:20 +0100 Subject: [PATCH 488/753] net tests --- rpc/src/v1/impls/net.rs | 4 +- rpc/src/v1/mod.rs | 3 +- rpc/src/v1/tests/helpers/mod.rs | 19 ++++++++ rpc/src/v1/tests/helpers/sync_provider.rs | 57 +++++++++++++++++++++++ rpc/src/v1/tests/mod.rs | 21 ++++++++- rpc/src/v1/tests/net.rs | 52 +++++++++++++++++++++ sync/src/chain.rs | 1 + 7 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 rpc/src/v1/tests/helpers/mod.rs create mode 100644 rpc/src/v1/tests/helpers/sync_provider.rs create mode 100644 rpc/src/v1/tests/net.rs diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 5e67bf252..1918073e3 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -36,10 +36,10 @@ impl NetClient where S: SyncProvider { impl Net for NetClient where S: SyncProvider + 'static { fn version(&self, _: Params) -> Result { - Ok(Value::U64(take_weak!(self.sync).status().protocol_version as u64)) + Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())) } fn peer_count(&self, _params: Params) -> Result { - Ok(Value::U64(take_weak!(self.sync).status().num_peers as u64)) + Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned())) } } diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 104a8b3f0..b82a20e89 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -21,9 +21,10 @@ pub mod traits; mod impls; mod types; +mod helpers; + #[cfg(test)] mod tests; -mod helpers; pub use self::traits::{Web3, Eth, EthFilter, Personal, Net}; pub use self::impls::*; diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs new file mode 100644 index 000000000..501bfb2d3 --- /dev/null +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -0,0 +1,19 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +mod sync_provider; + +pub use self::sync_provider::{Config, TestSyncProvider}; diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs new file mode 100644 index 000000000..b6d9241dd --- /dev/null +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -0,0 +1,57 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use ethcore::transaction::SignedTransaction; +use ethsync::{SyncProvider, SyncStatus, SyncState}; + +pub struct Config { + pub protocol_version: u8, + pub num_peers: usize, +} + +pub struct TestSyncProvider { + status: SyncStatus, +} + +impl TestSyncProvider { + pub fn new(config: Config) -> Self { + TestSyncProvider { + status: SyncStatus { + state: SyncState::NotSynced, + protocol_version: config.protocol_version, + start_block_number: 0, + last_imported_block_number: None, + highest_block_number: None, + blocks_total: 0, + blocks_received: 0, + num_peers: config.num_peers, + num_active_peers: 0, + mem_used: 0, + }, + } + } +} + +impl SyncProvider for TestSyncProvider { + fn status(&self) -> SyncStatus { + self.status.clone() + } + + fn insert_transaction(&self, _transaction: SignedTransaction) { + unimplemented!() + } +} + diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index bdf4567b6..5ef74987c 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -1 +1,20 @@ -//TODO: load custom blockchain state and test +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//!TODO: load custom blockchain state and test + +mod net; +mod helpers; diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs new file mode 100644 index 000000000..f6c4ae2e9 --- /dev/null +++ b/rpc/src/v1/tests/net.rs @@ -0,0 +1,52 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use jsonrpc_core::IoHandler; +use v1::{Net, NetClient}; +use v1::tests::helpers::{Config, TestSyncProvider}; + +#[test] +fn rpc_net_version() { + let sync = Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_version", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"65","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_string())); +} + +#[test] +fn rpc_net_peer_count() { + let sync = Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_peerCount", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x78","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_string())); +} diff --git a/sync/src/chain.rs b/sync/src/chain.rs index da3908a1e..da25c72de 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -120,6 +120,7 @@ pub enum SyncState { } /// Syncing status and statistics +#[derive(Clone)] pub struct SyncStatus { /// State pub state: SyncState, From 3bbdc03d0cbebe315a059ac7762db386805868f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 10:17:51 +0100 Subject: [PATCH 489/753] Fixing doctest. --- sync/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sync/src/lib.rs b/sync/src/lib.rs index e0158a564..d54acaf8a 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -31,18 +31,21 @@ //! extern crate ethcore_util as util; //! extern crate ethcore; //! extern crate ethsync; +//! extern crate ethminer; //! use std::env; //! use std::sync::Arc; //! use util::network::{NetworkService, NetworkConfiguration}; //! use ethcore::client::{Client, ClientConfig}; //! use ethsync::{EthSync, SyncConfig}; +//! use ethminer::Miner; //! use ethcore::ethereum; //! //! fn main() { //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let dir = env::temp_dir(); //! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); -//! EthSync::register(&mut service, SyncConfig::default(), client); +//! let miner = Miner::new(); +//! EthSync::register(&mut service, SyncConfig::default(), client, miner); //! } //! ``` From 8e52510dbb45642105f3fb4dab5e6fc166225fff Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 10:21:25 +0100 Subject: [PATCH 490/753] implemented net_listening method --- rpc/src/v1/impls/net.rs | 5 +++++ rpc/src/v1/tests/net.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 1918073e3..e52fc0bd4 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -42,4 +42,9 @@ impl Net for NetClient where S: SyncProvider + 'static { fn peer_count(&self, _params: Params) -> Result { Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned())) } + + fn is_listening(&self, _: Params) -> Result { + // right now (11 march 2016), we are always listening for incoming connections + Ok(Value::Bool(true)) + } } diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs index f6c4ae2e9..9cb0bd189 100644 --- a/rpc/src/v1/tests/net.rs +++ b/rpc/src/v1/tests/net.rs @@ -50,3 +50,19 @@ fn rpc_net_peer_count() { assert_eq!(io.handle_request(request), Some(response.to_string())); } + +#[test] +fn rpc_net_listening() { + let sync = Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_listening", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_string())); +} From a6d268db1618dea7bb2c6189a443777cb0760438 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 10:30:13 +0100 Subject: [PATCH 491/753] fixed missing reexport --- ethcore/src/blockchain/mod.rs | 2 +- ethcore/src/client/client.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 6559d8364..29a4ee684 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -23,9 +23,9 @@ mod bloom_indexer; mod cache; mod tree_route; mod update; +mod import_route; #[cfg(test)] mod generator; -mod import_route; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 4ef8bb029..40f86f7a2 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -37,8 +37,9 @@ use filter::Filter; use log_entry::LocalizedLogEntry; use util::keys::store::SecretStore; use block_queue::{BlockQueue, BlockQueueInfo}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, CacheSize as BlockChainCacheSize}; +use blockchain::{BlockChain, BlockProvider, TreeRoute}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; +pub use blockchain::CacheSize as BlockChainCacheSize; /// General block status #[derive(Debug, Eq, PartialEq)] From 3a4a7ac822289181229c16af58690e63e3b98b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 10:35:26 +0100 Subject: [PATCH 492/753] Bumping clippy version --- Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- util/Cargo.toml | 2 +- util/bigint/Cargo.toml | 1 - 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22d0f9288..70e4cbc34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } fdlimit = { path = "util/fdlimit" } daemonize = "0.2" number_prefix = "0.2" -clippy = { version = "0.0.44", optional = true } +clippy = { version = "0.0.49", optional = true } ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index fbfe175d7..b5c4a7636 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -21,7 +21,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.44", optional = true } +clippy = { version = "0.0.49", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 2ce430e51..918160be9 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,7 +18,7 @@ ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } -clippy = { version = "0.0.44", optional = true } +clippy = { version = "0.0.49", optional = true } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 46baa8a83..8412d3700 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -14,7 +14,7 @@ rustc_version = "0.1" [dependencies] ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } -clippy = { version = "0.0.44", optional = true } +clippy = { version = "0.0.49", optional = true } log = "0.3" env_logger = "0.3" time = "0.1.34" diff --git a/util/Cargo.toml b/util/Cargo.toml index 0ce27ec2b..93b475538 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -27,7 +27,7 @@ crossbeam = "0.2" slab = "0.1" sha3 = { path = "sha3" } serde = "0.7.0" -clippy = { version = "0.0.44", optional = true } +clippy = { version = "0.0.49", optional = true } json-tests = { path = "json-tests" } rustc_version = "0.1.0" igd = "0.4.2" diff --git a/util/bigint/Cargo.toml b/util/bigint/Cargo.toml index 377391eeb..1bd2b994e 100644 --- a/util/bigint/Cargo.toml +++ b/util/bigint/Cargo.toml @@ -15,7 +15,6 @@ rustc-serialize = "0.3" arrayvec = "0.3" rand = "0.3.12" serde = "0.7.0" -clippy = { version = "0.0.44", optional = true } heapsize = "0.3" [features] From 8709dd28f884742756ae4bbba9bd628708f271bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 10:57:58 +0100 Subject: [PATCH 493/753] Fixing clippy warnings --- Cargo.lock | 30 ++++++++++++------------------ ethcore/src/extras.rs | 14 ++++++++++---- ethcore/src/lib.rs | 2 ++ ethcore/src/substate.rs | 14 ++++++++++---- sync/src/chain.rs | 2 +- sync/src/lib.rs | 4 +++- sync/src/transaction_queue.rs | 8 ++++++++ util/src/keys/store.rs | 10 ++++++++-- util/src/kvdb.rs | 7 +++++++ util/src/lib.rs | 2 ++ util/src/memorydb.rs | 11 +++++++++-- util/src/network/discovery.rs | 9 ++++++++- util/src/network/host.rs | 9 ++++++++- util/src/panics.rs | 11 +++++++++-- util/src/rlp/rlpstream.rs | 17 +++++++++++++++-- util/src/table.rs | 13 ++++++++++++- util/src/trie/journal.rs | 7 +++++++ 17 files changed, 131 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f583a8747..e33e0288c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "parity" version = "0.9.99" dependencies = [ - "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -94,7 +94,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.44" +version = "0.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -207,7 +207,7 @@ dependencies = [ name = "ethcore" version = "0.9.99" dependencies = [ - "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", @@ -234,7 +234,7 @@ dependencies = [ name = "ethcore-rpc" version = "0.9.99" dependencies = [ - "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", "ethcore 0.9.99", "ethcore-util 0.9.99", @@ -258,7 +258,7 @@ dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", "chrono 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -273,7 +273,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.4.1 (git+https://github.com/arkpar/rust-rocksdb.git)", + "rocksdb 0.4.2 (git+https://github.com/arkpar/rust-rocksdb.git)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -290,7 +290,7 @@ dependencies = [ name = "ethsync" version = "0.9.99" dependencies = [ - "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", @@ -469,11 +469,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librocksdb-sys" -version = "0.2.1" -source = "git+https://github.com/arkpar/rust-rocksdb.git#2156621f583bda95c1c07e89e79e4019f75158ee" +version = "0.2.2" +source = "git+https://github.com/arkpar/rust-rocksdb.git#a4f89fea20ee3ae92b692df65d56426a5c0b6fd5" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -597,11 +596,6 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "pkg-config" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "primal" version = "0.2.3" @@ -697,11 +691,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" -version = "0.4.1" -source = "git+https://github.com/arkpar/rust-rocksdb.git#2156621f583bda95c1c07e89e79e4019f75158ee" +version = "0.4.2" +source = "git+https://github.com/arkpar/rust-rocksdb.git#a4f89fea20ee3ae92b692df65d56426a5c0b6fd5" dependencies = [ "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "librocksdb-sys 0.2.1 (git+https://github.com/arkpar/rust-rocksdb.git)", + "librocksdb-sys 0.2.2 (git+https://github.com/arkpar/rust-rocksdb.git)", ] [[package]] diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index f4759b040..a7c82c37c 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -35,13 +35,13 @@ pub enum ExtrasIndex { BlocksBlooms = 4, /// Block receipts index BlockReceipts = 5, -} +} /// trait used to write Extras data to db pub trait ExtrasWritable { /// Write extra data to db fn put_extras(&self, hash: &K, value: &T) where - T: ExtrasIndexable + Encodable, + T: ExtrasIndexable + Encodable, K: ExtrasSliceConvertable; } @@ -60,9 +60,9 @@ pub trait ExtrasReadable { impl ExtrasWritable for DBTransaction { fn put_extras(&self, hash: &K, value: &T) where - T: ExtrasIndexable + Encodable, + T: ExtrasIndexable + Encodable, K: ExtrasSliceConvertable { - + self.put(&hash.to_extras_slice(T::extras_index()), &encode(value)).unwrap() } } @@ -215,6 +215,12 @@ pub struct BlocksBlooms { pub blooms: [H2048; 16], } +impl Default for BlocksBlooms { + fn default() -> Self { + BlocksBlooms::new() + } +} + impl BlocksBlooms { pub fn new() -> Self { BlocksBlooms { blooms: unsafe { ::std::mem::zeroed() }} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 469364eb3..2209df7dc 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -25,6 +25,8 @@ #![cfg_attr(all(nightly, feature="dev"), allow(match_bool))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +// In most cases it expresses function flow better +#![cfg_attr(all(nightly, feature="dev"), allow(if_not_else))] //! Ethcore library //! diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 374397ca7..57e35ad2e 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -31,6 +31,12 @@ pub struct Substate { pub contracts_created: Vec
} +impl Default for Substate { + fn default() -> Self { + Substate::new() + } +} + impl Substate { /// Creates new substate. pub fn new() -> Self { @@ -67,8 +73,8 @@ mod tests { let mut sub_state = Substate::new(); sub_state.contracts_created.push(address_from_u64(1u64)); sub_state.logs.push(LogEntry { - address: address_from_u64(1u64), - topics: vec![], + address: address_from_u64(1u64), + topics: vec![], data: vec![] }); sub_state.sstore_clears_count = x!(5); @@ -77,8 +83,8 @@ mod tests { let mut sub_state_2 = Substate::new(); sub_state_2.contracts_created.push(address_from_u64(2u64)); sub_state_2.logs.push(LogEntry { - address: address_from_u64(1u64), - topics: vec![], + address: address_from_u64(1u64), + topics: vec![], data: vec![] }); sub_state_2.sstore_clears_count = x!(7); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index da3908a1e..a22f23eb8 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1307,7 +1307,7 @@ impl ChainSync { where T: Fn(&Address) -> U256 { let mut queue = self.transaction_queue.lock().unwrap(); - queue.add(transaction, fetch_nonce); + let _ = queue.add(transaction, fetch_nonce); } } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 3b79e5614..6cb98521e 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -17,9 +17,10 @@ #![warn(missing_docs)] #![cfg_attr(all(nightly, feature="dev"), feature(plugin))] #![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] - // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +// In most cases it expresses function flow better +#![cfg_attr(all(nightly, feature="dev"), allow(if_not_else))] //! Blockchain sync module //! Implements ethereum protocol version 63 as specified here: @@ -172,6 +173,7 @@ impl NetworkProtocolHandler for EthSync { self.sync.write().unwrap().maintain_sync(&mut NetSyncIo::new(io, self.chain.deref())); } + #[allow(single_match)] fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted } => { diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 243939a4c..45dc0e299 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -79,6 +79,7 @@ //! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated. //! +use std::default::Default; use std::cmp::{Ordering}; use std::collections::{HashMap, BTreeSet}; use util::numbers::{Uint, U256}; @@ -102,6 +103,7 @@ struct TransactionOrder { hash: H256, } + impl TransactionOrder { fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self { TransactionOrder { @@ -253,6 +255,12 @@ pub struct TransactionQueue { last_nonces: HashMap, } +impl Default for TransactionQueue { + fn default() -> Self { + TransactionQueue::new() + } +} + impl TransactionQueue { /// Creates new instance of this Queue pub fn new() -> Self { diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index dcc165259..7e12703ea 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -78,9 +78,15 @@ struct AccountUnlock { expires: DateTime, } +impl Default for SecretStore { + fn default() -> Self { + SecretStore::new() + } +} + impl SecretStore { /// new instance of Secret Store in default home directory - pub fn new() -> SecretStore { + pub fn new() -> Self { let mut path = ::std::env::home_dir().expect("Failed to get home dir"); path.push(".parity"); path.push("keys"); @@ -89,7 +95,7 @@ impl SecretStore { } /// new instance of Secret Store in specific directory - pub fn new_in(path: &Path) -> SecretStore { + pub fn new_in(path: &Path) -> Self { SecretStore { directory: KeyDirectory::new(path), unlocks: RwLock::new(HashMap::new()), diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index a2fa2215a..df5c2c448 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -16,6 +16,7 @@ //! Key-Value store abstraction with RocksDB backend. +use std::default::Default; use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBVector, DBIterator, IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction}; @@ -24,6 +25,12 @@ pub struct DBTransaction { batch: WriteBatch, } +impl Default for DBTransaction { + fn default() -> Self { + DBTransaction::new() + } +} + impl DBTransaction { /// Create new transaction. pub fn new() -> DBTransaction { diff --git a/util/src/lib.rs b/util/src/lib.rs index 59d66a325..bdb4be6e4 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -27,6 +27,8 @@ #![cfg_attr(all(nightly, feature="dev"), allow(match_same_arms))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. #![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +// In most cases it expresses function flow better +#![cfg_attr(all(nightly, feature="dev"), allow(if_not_else))] //! Ethcore-util library //! diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index 9cd018935..66fa32055 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -24,6 +24,7 @@ use hashdb::*; use heapsize::*; use std::mem; use std::collections::HashMap; +use std::default::Default; #[derive(Debug,Clone)] /// Reference-counted memory-based HashDB implementation. @@ -32,7 +33,7 @@ use std::collections::HashMap; /// with `kill()`, check for existance with `exists()` and lookup a hash to derive /// the data with `lookup()`. Clear with `clear()` and purge the portions of the data /// that have no references with `purge()`. -/// +/// /// # Example /// ```rust /// extern crate ethcore_util; @@ -74,6 +75,12 @@ pub struct MemoryDB { static_null_rlp: (Bytes, i32), } +impl Default for MemoryDB { + fn default() -> Self { + MemoryDB::new() + } +} + impl MemoryDB { /// Create a new instance of the memory DB. pub fn new() -> MemoryDB { @@ -133,7 +140,7 @@ impl MemoryDB { /// Denote than an existing value has the given key. Used when a key gets removed without /// a prior insert and thus has a negative reference with no value. - /// + /// /// May safely be called even if the key's value is known, in which case it will be a no-op. pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) { if self.raw(key) == None { diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 644af22af..2e7c51cb0 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -19,6 +19,7 @@ use std::net::SocketAddr; use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; use std::mem; use std::cmp; +use std::default::Default; use mio::*; use mio::udp::*; use sha3::*; @@ -62,8 +63,14 @@ struct NodeBucket { nodes: VecDeque, //sorted by last active } +impl Default for NodeBucket { + fn default() -> Self { + NodeBucket::new() + } +} + impl NodeBucket { - fn new() -> NodeBucket { + fn new() -> Self { NodeBucket { nodes: VecDeque::new() } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 2d1af55ba..3db94131a 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -23,6 +23,7 @@ use std::ops::*; use std::cmp::min; use std::path::{Path, PathBuf}; use std::io::{Read, Write}; +use std::default::Default; use std::fs; use mio::*; use mio::tcp::*; @@ -75,9 +76,15 @@ pub struct NetworkConfiguration { pub ideal_peers: u32, } +impl Default for NetworkConfiguration { + fn default() -> Self { + NetworkConfiguration::new() + } +} + impl NetworkConfiguration { /// Create a new instance of default settings. - pub fn new() -> NetworkConfiguration { + pub fn new() -> Self { NetworkConfiguration { config_path: None, listen_address: None, diff --git a/util/src/panics.rs b/util/src/panics.rs index 70ce0bc33..ab25eae57 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -19,6 +19,7 @@ use std::thread; use std::ops::DerefMut; use std::sync::{Arc, Mutex}; +use std::default::Default; /// Thread-safe closure for handling possible panics pub trait OnPanicListener: Send + Sync + 'static { @@ -56,14 +57,20 @@ pub struct PanicHandler { listeners: Mutex>> } +impl Default for PanicHandler { + fn default() -> Self { + PanicHandler::new() + } +} + impl PanicHandler { /// Creates new `PanicHandler` wrapped in `Arc` - pub fn new_in_arc() -> Arc { + pub fn new_in_arc() -> Arc { Arc::new(Self::new()) } /// Creates new `PanicHandler` - pub fn new() -> PanicHandler { + pub fn new() -> Self { PanicHandler { listeners: Mutex::new(vec![]) } diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index ba70e7b2b..7bf3d3cdd 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::ops::Deref; +use std::default::Default; use elastic_array::*; use rlp::bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; @@ -44,6 +45,12 @@ pub struct RlpStream { finished_list: bool, } +impl Default for RlpStream { + fn default() -> Self { + RlpStream::new() + } +} + impl Stream for RlpStream { fn new() -> Self { RlpStream { @@ -190,8 +197,14 @@ struct BasicEncoder { bytes: ElasticArray1024, } +impl Default for BasicEncoder { + fn default() -> Self { + BasicEncoder::new() + } +} + impl BasicEncoder { - fn new() -> BasicEncoder { + fn new() -> Self { BasicEncoder { bytes: ElasticArray1024::new() } } @@ -222,7 +235,7 @@ impl Encoder for BasicEncoder { // just 0 0 => self.bytes.push(0x80u8), // byte is its own encoding if < 0x80 - 1 => { + 1 => { value.to_bytes(&mut self.bytes); let len = self.bytes.len(); let last_byte = self.bytes[len - 1]; diff --git a/util/src/table.rs b/util/src/table.rs index e41209608..5ba572289 100644 --- a/util/src/table.rs +++ b/util/src/table.rs @@ -16,6 +16,7 @@ //! A collection associating pair of keys (row and column) with a single value. +use std::default::Default; use std::hash::Hash; use std::collections::HashMap; @@ -30,11 +31,21 @@ pub struct Table map: HashMap>, } +impl Default for Table + where Row: Eq + Hash + Clone, + Col: Eq + Hash { + fn default() -> Self { + Table::new() + } +} + +// There is default but clippy does not detect it? +#[allow(new_without_default)] impl Table where Row: Eq + Hash + Clone, Col: Eq + Hash { /// Creates new Table - pub fn new() -> Table { + pub fn new() -> Self { Table { map: HashMap::new(), } diff --git a/util/src/trie/journal.rs b/util/src/trie/journal.rs index db16a313d..4ffd7cf5c 100644 --- a/util/src/trie/journal.rs +++ b/util/src/trie/journal.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::default::Default; use sha3::*; use hash::H256; use bytes::*; @@ -39,6 +40,12 @@ pub struct Score { #[derive(Debug)] pub struct Journal (Vec); +impl Default for Journal { + fn default() -> Self { + Journal::new() + } +} + impl Journal { /// Create a new, empty, object. pub fn new() -> Journal { Journal(vec![]) } From 18939462c392a3c175b69dc6002454c7baeb55ca Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 11:03:43 +0100 Subject: [PATCH 494/753] sync_provider function --- rpc/src/v1/tests/net.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs index 9cb0bd189..792e469d8 100644 --- a/rpc/src/v1/tests/net.rs +++ b/rpc/src/v1/tests/net.rs @@ -19,12 +19,16 @@ use jsonrpc_core::IoHandler; use v1::{Net, NetClient}; use v1::tests::helpers::{Config, TestSyncProvider}; -#[test] -fn rpc_net_version() { - let sync = Arc::new(TestSyncProvider::new(Config { +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { protocol_version: 65, num_peers: 120, - })); + })) +} + +#[test] +fn rpc_net_version() { + let sync = sync_provider(); let net = NetClient::new(&sync).to_delegate(); let io = IoHandler::new(); io.add_delegate(net); @@ -37,10 +41,7 @@ fn rpc_net_version() { #[test] fn rpc_net_peer_count() { - let sync = Arc::new(TestSyncProvider::new(Config { - protocol_version: 65, - num_peers: 120, - })); + let sync = sync_provider(); let net = NetClient::new(&sync).to_delegate(); let io = IoHandler::new(); io.add_delegate(net); @@ -53,10 +54,7 @@ fn rpc_net_peer_count() { #[test] fn rpc_net_listening() { - let sync = Arc::new(TestSyncProvider::new(Config { - protocol_version: 65, - num_peers: 120, - })); + let sync = sync_provider(); let net = NetClient::new(&sync).to_delegate(); let io = IoHandler::new(); io.add_delegate(net); From a8a21da9ba7942615a6bbf031fc0ac78e9bc83f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 11:05:20 +0100 Subject: [PATCH 495/753] Updating hook and removing running clippy from dev-dependencies --- Cargo.toml | 6 ------ hook.sh | 13 +++++++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22d0f9288..563dd2a69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,12 +27,6 @@ ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } rpassword = "0.1" -[dev-dependencies] -ethcore = { path = "ethcore", features = ["dev"] } -ethcore-util = { path = "util", features = ["dev"] } -ethsync = { path = "sync", features = ["dev"] } -ethcore-rpc = { path = "rpc", features = ["dev"] } - [features] default = ["rpc"] rpc = ["ethcore-rpc"] diff --git a/hook.sh b/hook.sh index 354fddd5d..aa6ed7415 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,12 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --features dev-clippy" > ./.git/hooks/pre-push -chmod +x ./.git/hooks/pre-push +FILE=./.git/hooks/pre-push +echo "#!/bin/sh\n" > $FILE +# Exit on any error +echo "set -e" >> $FILE +# Run release build +echo "cargo build --release --features dev-clippy" >> $FILE +# Build tests +echo "cargo test --no-run --features dev-clippy \\" >> $FILE +echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" >> $FILE +echo "" >> $FILE +chmod +x $FILE From d84e008e00b23d64d6bee1920cc545b434f5348d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 11:16:49 +0100 Subject: [PATCH 496/753] Removing superflous check for nightly --- Cargo.toml | 5 ++--- cargo.sh | 2 -- ethcore/Cargo.toml | 6 +----- ethcore/build.rs | 25 ------------------------- ethcore/src/basic_types.rs | 2 +- ethcore/src/block.rs | 2 +- ethcore/src/block_queue.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 4 ++-- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/evm/interpreter.rs | 6 +++--- ethcore/src/externalities.rs | 2 +- ethcore/src/lib.rs | 10 +++++----- ethcore/src/service.rs | 2 +- ethcore/src/spec.rs | 2 +- ethcore/src/state.rs | 2 +- ethcore/src/transaction.rs | 2 +- hook.sh | 4 ++-- parity/main.rs | 6 +++--- rpc/Cargo.toml | 3 +-- rpc/build.rs | 7 ------- sync/Cargo.toml | 6 +----- sync/build.rs | 25 ------------------------- sync/src/chain.rs | 6 +++--- sync/src/lib.rs | 6 +++--- sync/src/range_collection.rs | 4 ++-- util/Cargo.toml | 3 +-- util/bigint/src/uint.rs | 6 +++--- util/build.rs | 5 ----- util/src/hash.rs | 4 ++-- util/src/lib.rs | 12 ++++++------ util/src/network/discovery.rs | 2 +- util/src/network/host.rs | 4 ++-- util/src/panics.rs | 2 +- util/src/trie/triedb.rs | 2 +- util/src/trie/triedbmut.rs | 4 ++-- 35 files changed, 56 insertions(+), 131 deletions(-) delete mode 100755 cargo.sh delete mode 100644 ethcore/build.rs delete mode 100644 sync/build.rs diff --git a/Cargo.toml b/Cargo.toml index 563dd2a69..4daabf669 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,10 +30,9 @@ rpassword = "0.1" [features] default = ["rpc"] rpc = ["ethcore-rpc"] -dev = ["ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] -dev-clippy = ["clippy", "ethcore/clippy", "ethcore-util/clippy", "ethsync/clippy", "ethcore-rpc/clippy"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] travis-beta = ["ethcore/json-tests"] -travis-nightly = ["ethcore/json-tests", "dev-clippy", "dev"] +travis-nightly = ["ethcore/json-tests", "dev"] [[bin]] path = "parity/main.rs" diff --git a/cargo.sh b/cargo.sh deleted file mode 100755 index 6870ab385..000000000 --- a/cargo.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -cargo "$@" --features dev-clippy diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index fbfe175d7..c3a3d32dc 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -5,10 +5,6 @@ license = "GPL-3.0" name = "ethcore" version = "0.9.99" authors = ["Ethcore "] -build = "build.rs" - -[build-dependencies] -rustc_version = "0.1" [dependencies] log = "0.3" @@ -31,5 +27,5 @@ jit = ["evmjit"] evm-debug = [] json-tests = [] test-heavy = [] -dev = [] +dev = ["clippy"] default = [] diff --git a/ethcore/build.rs b/ethcore/build.rs deleted file mode 100644 index 41b9a1b3e..000000000 --- a/ethcore/build.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -extern crate rustc_version; - -use rustc_version::{version_meta, Channel}; - -fn main() { - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } -} diff --git a/ethcore/src/basic_types.rs b/ethcore/src/basic_types.rs index 9cba8b3a0..5f6515c0d 100644 --- a/ethcore/src/basic_types.rs +++ b/ethcore/src/basic_types.rs @@ -24,7 +24,7 @@ pub type LogBloom = H2048; /// Constant 2048-bit datum for 0. Often used as a default. pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); -#[cfg_attr(all(nightly, feature="dev"), allow(enum_variant_names))] +#[cfg_attr(feature="dev", allow(enum_variant_names))] /// Semantic boolean for when a seal/signature is included. pub enum Seal { /// The seal/signature is included. diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index b3894db94..9ecd58e0a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -16,7 +16,7 @@ //! Blockchain block. -#![cfg_attr(all(nightly, feature="dev"), allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> +#![cfg_attr(feature="dev", allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> use common::*; use engine::*; diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 3dfb98e8a..c83542f12 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -121,7 +121,7 @@ struct QueueSignal { } impl QueueSignal { - #[cfg_attr(all(nightly, feature="dev"), allow(bool_comparison))] + #[cfg_attr(feature="dev", allow(bool_comparison))] fn set(&self) { if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false { self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message"); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8c21532c8..d67c1b7f1 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -891,7 +891,7 @@ mod tests { } #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_find_uncles() { let mut canon_chain = ChainGenerator::default(); let mut finalizer = BlockFinalizer::default(); @@ -929,7 +929,7 @@ mod tests { } #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { let mut canon_chain = ChainGenerator::default(); let mut finalizer = BlockFinalizer::default(); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index b0c0e4a9f..f9810b964 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -202,7 +202,7 @@ impl Engine for Ethash { } } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] // to_ethash should take self +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // to_ethash should take self impl Ethash { fn calculate_difficuty(&self, header: &Header, parent: &Header) -> U256 { const EXP_DIFF_PERIOD: u64 = 100000; diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index fb8d19357..7491321cb 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -243,7 +243,7 @@ struct CodeReader<'a> { code: &'a Bytes } -#[cfg_attr(all(nightly, feature="dev"), allow(len_without_is_empty))] +#[cfg_attr(feature="dev", allow(len_without_is_empty))] impl<'a> CodeReader<'a> { /// Get `no_of_bytes` from code and convert to U256. Move PC fn read(&mut self, no_of_bytes: usize) -> U256 { @@ -258,7 +258,7 @@ impl<'a> CodeReader<'a> { } } -#[cfg_attr(all(nightly, feature="dev"), allow(enum_variant_names))] +#[cfg_attr(feature="dev", allow(enum_variant_names))] enum InstructionCost { Gas(U256), GasMem(U256, U256), @@ -347,7 +347,7 @@ impl evm::Evm for Interpreter { } impl Interpreter { - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn get_gas_cost_mem(&self, ext: &evm::Ext, instruction: Instruction, diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index a1f5763ea..598921580 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -188,7 +188,7 @@ impl<'a> Ext for Externalities<'a> { self.state.code(address).unwrap_or_else(|| vec![]) } - #[cfg_attr(all(nightly, feature="dev"), allow(match_ref_pats))] + #[cfg_attr(feature="dev", allow(match_ref_pats))] fn ret(&mut self, gas: &U256, data: &[u8]) -> Result { match &mut self.output { &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 469364eb3..938da02a0 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -15,16 +15,16 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // Clippy config // TODO [todr] not really sure -#![cfg_attr(all(nightly, feature="dev"), allow(needless_range_loop))] +#![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![cfg_attr(all(nightly, feature="dev"), allow(match_bool))] +#![cfg_attr(feature="dev", allow(match_bool))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Ethcore library //! diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index bd15ee501..6daf0d7b6 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -117,7 +117,7 @@ impl IoHandler for ClientIoHandler { } } - #[cfg_attr(all(nightly, feature="dev"), allow(single_match))] + #[cfg_attr(feature="dev", allow(single_match))] fn message(&self, io: &IoContext, net_message: &NetSyncMessage) { if let UserMessage(ref message) = *net_message { match *message { diff --git a/ethcore/src/spec.rs b/ethcore/src/spec.rs index 774024351..2208350cc 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec.rs @@ -99,7 +99,7 @@ pub struct Spec { genesis_state: PodState, } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) impl Spec { /// Convert this object into a boxed Engine of the right underlying type. // TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead. diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 7c1064abf..c13678c38 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -224,7 +224,7 @@ impl State { /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. - #[cfg_attr(all(nightly, feature="dev"), allow(match_ref_pats))] + #[cfg_attr(feature="dev", allow(match_ref_pats))] pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { // first, commit the sub trees. // TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 733e5ac6b..a51824494 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -80,7 +80,7 @@ impl Transaction { } impl FromJson for SignedTransaction { - #[cfg_attr(all(nightly, feature="dev"), allow(single_char_pattern))] + #[cfg_attr(feature="dev", allow(single_char_pattern))] fn from_json(json: &Json) -> SignedTransaction { let t = Transaction { nonce: xjson!(&json["nonce"]), diff --git a/hook.sh b/hook.sh index aa6ed7415..9780541fe 100755 --- a/hook.sh +++ b/hook.sh @@ -4,9 +4,9 @@ echo "#!/bin/sh\n" > $FILE # Exit on any error echo "set -e" >> $FILE # Run release build -echo "cargo build --release --features dev-clippy" >> $FILE +echo "cargo build --release --features dev" >> $FILE # Build tests -echo "cargo test --no-run --features dev-clippy \\" >> $FILE +echo "cargo test --no-run --features dev \\" >> $FILE echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" >> $FILE echo "" >> $FILE chmod +x $FILE diff --git a/parity/main.rs b/parity/main.rs index efff52e4e..c38c2d515 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -17,8 +17,8 @@ //! Ethcore client application. #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] extern crate docopt; extern crate rustc_serialize; extern crate ethcore_util as util; @@ -293,7 +293,7 @@ impl Configuration { } } - #[cfg_attr(all(nightly, feature="dev"), allow(useless_format))] + #[cfg_attr(feature="dev", allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { let mut listen_address = None; let mut public_address = None; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 2ce430e51..f324aba10 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -26,9 +26,8 @@ serde_macros = { version = "0.7.0", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } syntex = "0.29.0" -rustc_version = "0.1" [features] default = ["serde_codegen"] nightly = ["serde_macros"] -dev = ["ethcore/dev", "ethcore-util/dev", "ethsync/dev"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev"] diff --git a/rpc/build.rs b/rpc/build.rs index 3806f6fe5..659bc35eb 100644 --- a/rpc/build.rs +++ b/rpc/build.rs @@ -14,10 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -extern crate rustc_version; - -use rustc_version::{version_meta, Channel}; - #[cfg(not(feature = "serde_macros"))] mod inner { extern crate syntex; @@ -46,7 +42,4 @@ mod inner { fn main() { inner::main(); - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 46baa8a83..0097cd47e 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -4,13 +4,9 @@ name = "ethsync" version = "0.9.99" license = "GPL-3.0" authors = ["Ethcore . - -extern crate rustc_version; - -use rustc_version::{version_meta, Channel}; - -fn main() { - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } -} diff --git a/sync/src/chain.rs b/sync/src/chain.rs index da3908a1e..7789fb004 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -275,7 +275,7 @@ impl ChainSync { } - #[cfg_attr(all(nightly, feature="dev"), allow(for_kv_map))] // Because it's not possible to get `values_mut()` + #[cfg_attr(feature="dev", allow(for_kv_map))] // Because it's not possible to get `values_mut()` /// Rest sync. Clear all downloaded data but keep the queue fn reset(&mut self) { self.downloading_headers.clear(); @@ -343,7 +343,7 @@ impl ChainSync { Ok(()) } - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Called by peer once it has new block headers during sync fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders); @@ -470,7 +470,7 @@ impl ChainSync { } /// Called by peer once it has new block bodies - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { let block_rlp = try!(r.at(0)); let header_rlp = try!(block_rlp.at(0)); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 3b79e5614..3ef4b4150 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -15,11 +15,11 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Blockchain sync module //! Implements ethereum protocol version 63 as specified here: diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index 826a67121..664d7c7a3 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -42,7 +42,7 @@ pub trait RangeCollection { fn remove_head(&mut self, start: &K); /// Remove all elements >= `start` in the range that contains `start` fn remove_tail(&mut self, start: &K); - /// Remove all elements >= `start` + /// Remove all elements >= `start` fn remove_from(&mut self, start: &K); /// Remove all elements >= `tail` fn insert_item(&mut self, key: K, value: V); @@ -231,7 +231,7 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } #[test] -#[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] +#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_range() { use std::cmp::{Ordering}; diff --git a/util/Cargo.toml b/util/Cargo.toml index 0ce27ec2b..74e4d7226 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -40,8 +40,7 @@ chrono = "0.2" [features] default = [] -dev = [] +dev = ["clippy"] [build-dependencies] vergen = "*" -rustc_version = "0.1" diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 959df0944..32abdb5d5 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -1103,7 +1103,7 @@ macro_rules! construct_uint { } } - #[cfg_attr(all(nightly, feature="dev"), allow(derive_hash_xor_eq))] // We are pretty sure it's ok. + #[cfg_attr(feature="dev", allow(derive_hash_xor_eq))] // We are pretty sure it's ok. impl Hash for $name { fn hash(&self, state: &mut H) where H: Hasher { unsafe { state.write(::std::slice::from_raw_parts(self.0.as_ptr() as *mut u8, self.0.len() * 8)); } @@ -1485,7 +1485,7 @@ mod tests { } #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(eq_op))] + #[cfg_attr(feature="dev", allow(eq_op))] pub fn uint256_comp_test() { let small = U256([10u64, 0, 0, 0]); let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); @@ -2032,7 +2032,7 @@ mod tests { #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn u256_multi_full_mul() { let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0])); assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result); diff --git a/util/build.rs b/util/build.rs index 0b9b233e0..b0b64a380 100644 --- a/util/build.rs +++ b/util/build.rs @@ -14,15 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -extern crate rustc_version; extern crate vergen; use vergen::*; -use rustc_version::{version_meta, Channel}; fn main() { vergen(OutputFns::all()).unwrap(); - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } } diff --git a/util/src/hash.rs b/util/src/hash.rs index 4eb96b53e..73fa33b47 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -305,7 +305,7 @@ macro_rules! impl_hash { } impl Copy for $from {} - #[cfg_attr(all(nightly, feature="dev"), allow(expl_impl_clone_on_copy))] + #[cfg_attr(feature="dev", allow(expl_impl_clone_on_copy))] impl Clone for $from { fn clone(&self) -> $from { unsafe { @@ -637,7 +637,7 @@ mod tests { use std::str::FromStr; #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(eq_op))] + #[cfg_attr(feature="dev", allow(eq_op))] fn hash() { let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); diff --git a/util/src/lib.rs b/util/src/lib.rs index 59d66a325..a50ba8da4 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -15,18 +15,18 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // Clippy settings // TODO [todr] not really sure -#![cfg_attr(all(nightly, feature="dev"), allow(needless_range_loop))] +#![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![cfg_attr(all(nightly, feature="dev"), allow(match_bool))] +#![cfg_attr(feature="dev", allow(match_bool))] // We use that to be more explicit about handled cases -#![cfg_attr(all(nightly, feature="dev"), allow(match_same_arms))] +#![cfg_attr(feature="dev", allow(match_same_arms))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Ethcore-util library //! diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 644af22af..4f3384894 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -243,7 +243,7 @@ impl Discovery { self.send_to(packet, address.clone()); } - #[cfg_attr(all(nightly, feature="dev"), allow(map_clone))] + #[cfg_attr(feature="dev", allow(map_clone))] fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { let mut found: BTreeMap> = BTreeMap::new(); let mut count = 0; diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 2d1af55ba..ece24a1d1 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -507,7 +507,7 @@ impl Host where Message: Send + Sync + Clone { debug!(target: "network", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); } - #[cfg_attr(all(nightly, feature="dev"), allow(single_match))] + #[cfg_attr(feature="dev", allow(single_match))] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { @@ -542,7 +542,7 @@ impl Host where Message: Send + Sync + Clone { self.create_connection(socket, Some(id), io); } - #[cfg_attr(all(nightly, feature="dev"), allow(block_in_if_condition_stmt))] + #[cfg_attr(feature="dev", allow(block_in_if_condition_stmt))] fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) { let nonce = self.info.write().unwrap().next_nonce(); let mut handshakes = self.handshakes.write().unwrap(); diff --git a/util/src/panics.rs b/util/src/panics.rs index 70ce0bc33..05d266b8b 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -71,7 +71,7 @@ impl PanicHandler { /// Invoke closure and catch any possible panics. /// In case of panic notifies all listeners about it. - #[cfg_attr(all(nightly, feature="dev"), allow(deprecated))] + #[cfg_attr(feature="dev", allow(deprecated))] pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { let _guard = PanicGuard { handler: self }; let result = g(); diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index 182b87063..06076d273 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -54,7 +54,7 @@ pub struct TrieDB<'db> { pub hash_count: usize, } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDB<'db> { /// Create a new trie with the backing database `db` and `root` /// Panics, if `root` does not exist diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 3d5c366e5..3d75fa3e1 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -66,7 +66,7 @@ enum MaybeChanged<'a> { Changed(Bytes), } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDBMut<'db> { /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. @@ -350,7 +350,7 @@ impl<'db> TrieDBMut<'db> { } } - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Determine the RLP of the node, assuming we're inserting `partial` into the /// node currently of data `old`. This will *not* delete any hash of `old` from the database; /// it will just return the new RLP that includes the new node. From eb8e92c37f7ffca670c2c9790f3a585141ab6c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 11:18:38 +0100 Subject: [PATCH 497/753] Cargo.lock --- Cargo.lock | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f583a8747..627fbfa69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,7 +219,6 @@ dependencies = [ "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -243,7 +242,6 @@ dependencies = [ "jsonrpc-http-server 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -299,7 +297,6 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] From 55a14b3aaf31e8b1f7b14d4eb75032a1fa815561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 11:40:12 +0100 Subject: [PATCH 498/753] Fixing transaction queue test --- Cargo.lock | 1 + miner/src/lib.rs | 1 + miner/src/transaction_queue.rs | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b49a974c..8b24df187 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,6 +299,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 0cee4ef43..20b5dd7d3 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -62,5 +62,6 @@ extern crate rayon; mod miner; mod transaction_queue; +pub use transaction_queue::TransactionQueue; pub use miner::{Miner, MinerService}; diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index f64bd7318..3d5c38b0c 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -28,13 +28,13 @@ //! ```rust //! extern crate ethcore_util as util; //! extern crate ethcore; -//! extern crate ethsync; +//! extern crate ethminer; //! extern crate rustc_serialize; //! //! use util::crypto::KeyPair; //! use util::hash::Address; //! use util::numbers::{Uint, U256}; -//! use ethsync::TransactionQueue; +//! use ethminer::TransactionQueue; //! use ethcore::transaction::*; //! use rustc_serialize::hex::FromHex; //! From 68a13973a4c9e6151c77465d7798b68ed3fec75f Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 11:42:24 +0100 Subject: [PATCH 499/753] fixed ethcore-rpc tests build after merge --- rpc/src/v1/tests/helpers/sync_provider.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index b6d9241dd..a3711d949 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -40,6 +40,7 @@ impl TestSyncProvider { num_peers: config.num_peers, num_active_peers: 0, mem_used: 0, + transaction_queue_pending: 0, }, } } From 8f54c24e47032a52bdbc9bd48cb2f16c7c9aa888 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 11 Mar 2016 11:52:11 +0100 Subject: [PATCH 500/753] Merged changes from jdb_option1, keep LATEST_ERA from decreasing --- ethcore/src/account_db.rs | 9 +- util/src/journaldb.rs | 347 +++++++++++++++++++++++++++++++++++--- util/src/memorydb.rs | 1 + 3 files changed, 323 insertions(+), 34 deletions(-) diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index e7f1b2bad..026e813f5 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -13,17 +13,14 @@ pub struct AccountDB<'db> { #[inline] fn combine_key<'a>(address: &'a H256, key: &'a H256) -> H256 { - let mut addr_hash = address.sha3(); - // preserve 96 bits of original key for db lookup - addr_hash[0..12].clone_from_slice(&[0u8; 12]); - &addr_hash ^ key + address ^ key } impl<'db> AccountDB<'db> { pub fn new(db: &'db HashDB, address: &Address) -> AccountDB<'db> { AccountDB { db: db, - address: x!(address.clone()), + address: x!(address), } } } @@ -70,7 +67,7 @@ impl<'db> AccountDBMut<'db> { pub fn new(db: &'db mut HashDB, address: &Address) -> AccountDBMut<'db> { AccountDBMut { db: db, - address: x!(address.clone()), + address: x!(address), } } diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 4f2cdeb31..8bff08a77 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -64,11 +64,14 @@ pub struct JournalDB { journal_overlay: Option>>, } +#[derive(PartialEq)] struct JournalOverlay { backing_overlay: MemoryDB, - journal: HashMap> + journal: HashMap>, + latest_era: u64, } +#[derive(PartialEq)] struct JournalEntry { id: H256, insertions: Vec, @@ -220,7 +223,10 @@ impl JournalDB { k.append(&index); k.append(&&PADDING[..]); try!(batch.put(&k.drain(), r.as_raw())); - try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + if now >= journal_overlay.latest_era { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + journal_overlay.latest_era = now; + } journal_overlay.journal.entry(now).or_insert_with(Vec::new).push(JournalEntry { id: id.clone(), insertions: inserted_keys, deletions: removed_keys }); } @@ -243,7 +249,7 @@ impl JournalDB { { if canon_id == journal.id { for h in &journal.insertions { - if let Some(&(ref d, rc)) = journal_overlay.backing_overlay.raw(h) { + if let Some(&(ref d, rc)) = journal_overlay.backing_overlay.raw(h) { if rc > 0 { canon_insertions.push((h.clone(), d.clone())); //TODO: optimize this to avoid data copy } @@ -253,17 +259,17 @@ impl JournalDB { } overlay_deletions.append(&mut journal.insertions); } - index +=1; + index += 1; } // apply canon inserts first for (k, v) in canon_insertions { try!(batch.put(&k, &v)); } - // clean the overlay + // update the overlay for k in overlay_deletions { journal_overlay.backing_overlay.kill(&k); } - // apply removes + // apply canon deletions for k in canon_deletions { if !journal_overlay.backing_overlay.exists(&k) { try!(batch.delete(&k)); @@ -277,6 +283,13 @@ impl JournalDB { Ok(()) } + #[cfg(test)] + fn can_reconstruct_refs(&self) -> bool { + let reconstructed = Self::read_overlay(&self.backing); + let journal_overlay = self.journal_overlay.as_ref().unwrap().read().unwrap(); + *journal_overlay == reconstructed + } + fn payload(&self, key: &H256) -> Option { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } @@ -285,8 +298,10 @@ impl JournalDB { let mut journal = HashMap::new(); let mut overlay = MemoryDB::new(); let mut count = 0; + let mut latest_era = 0; if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); + latest_era = decode::(&val); + let mut era = latest_era; loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ @@ -296,7 +311,7 @@ impl JournalDB { r.append(&&PADDING[..]); &r.drain() }).expect("Low-level database error.") { - trace!("read_counters: era={}, index={}", era, index); + trace!("read_overlay: era={}, index={}", era, index); let rlp = Rlp::new(&rlp_data); let id: H256 = rlp.val_at(0); let insertions = rlp.at(1); @@ -323,7 +338,7 @@ impl JournalDB { } } trace!("Recovered {} overlay entries, {} journal entries", count, journal.len()); - JournalOverlay { backing_overlay: overlay, journal: journal } + JournalOverlay { backing_overlay: overlay, journal: journal, latest_era: latest_era } } /// Returns heap memory size used @@ -396,6 +411,7 @@ mod tests { use common::*; use super::*; use hashdb::*; + use log::init_log; #[test] fn insert_same_in_fork() { @@ -404,17 +420,25 @@ mod tests { let x = jdb.insert(b"X"); jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(3, &b"1002a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(4, &b"1003a".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&x); jdb.commit(3, &b"1002b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); let x = jdb.insert(b"X"); jdb.commit(4, &b"1003b".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(5, &b"1004a".sha3(), Some((3, b"1002a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(6, &b"1005a".sha3(), Some((4, b"1003a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&x)); } @@ -425,15 +449,20 @@ mod tests { let mut jdb = JournalDB::new_temp(); let h = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.remove(&h); jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&h)); } @@ -445,6 +474,7 @@ mod tests { let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); @@ -452,6 +482,7 @@ mod tests { jdb.remove(&bar); let baz = jdb.insert(b"baz"); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); assert!(jdb.exists(&baz)); @@ -459,17 +490,20 @@ mod tests { let foo = jdb.insert(b"foo"); jdb.remove(&baz); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&bar)); assert!(jdb.exists(&baz)); jdb.remove(&foo); jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&bar)); assert!(!jdb.exists(&baz)); jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); assert!(!jdb.exists(&bar)); assert!(!jdb.exists(&baz)); @@ -483,21 +517,25 @@ mod tests { let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.remove(&foo); let baz = jdb.insert(b"baz"); jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&bar); jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); assert!(jdb.exists(&baz)); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&baz)); assert!(!jdb.exists(&bar)); @@ -510,35 +548,113 @@ mod tests { let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.insert(b"foo"); assert!(jdb.exists(&foo)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); jdb.commit(3, &b"2".sha3(), Some((0, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); } #[test] - fn fork_same_key() { - // history is 1 - let mut jdb = JournalDB::new_temp(); + fn fork_same_key_one() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); let foo = jdb.insert(b"foo"); jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.insert(b"foo"); jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); } + #[test] + fn fork_same_key_other() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_ins_del_ins() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(4, &b"4a".sha3(), Some((2, b"2a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5a".sha3(), Some((3, b"3a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } #[test] fn reopen() { @@ -552,6 +668,7 @@ mod tests { let foo = jdb.insert(b"foo"); jdb.emplace(bar.clone(), b"bar".to_vec()); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); foo }; @@ -559,6 +676,7 @@ mod tests { let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); } { @@ -566,41 +684,210 @@ mod tests { assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); } } #[test] - fn reopen_remove() { + fn insert_delete_insert_delete_insert_expunge() { + init_log(); let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let foo = { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); - // history is 1 - let foo = jdb.insert(b"foo"); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); - // foo is ancient history. + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } - jdb.insert(b"foo"); - jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); - foo - }; + #[test] + fn forked_insert_delete_insert_delete_insert_expunge() { + init_log(); + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn broken_assert() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); // BROKEN + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + + #[test] + fn reopen_test() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.remove(&bar); + jdb.commit(6, &b"6".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.insert(b"bar"); + jdb.commit(7, &b"7".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn reopen_remove_three() { + init_log(); + + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let foo = b"foo".sha3(); { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + jdb.remove(&foo); - jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + jdb.commit(2, &b"2".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); - jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); - jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + jdb.commit(4, &b"4".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + + jdb.commit(5, &b"5".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + + jdb.commit(6, &b"6".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); } } - + #[test] fn reopen_fork() { let mut dir = ::std::env::temp_dir(); @@ -611,18 +898,22 @@ mod tests { let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&foo); let baz = jdb.insert(b"baz"); jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&bar); jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); (foo, bar, baz) }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&baz)); assert!(!jdb.exists(&bar)); diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index 9cd018935..dd8de7fd8 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -69,6 +69,7 @@ use std::collections::HashMap; /// assert!(!m.exists(&k)); /// } /// ``` +#[derive(PartialEq)] pub struct MemoryDB { data: HashMap, static_null_rlp: (Bytes, i32), From dd2fb4df67307c4ce8e632d7ab009937422888af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 12:31:42 +0100 Subject: [PATCH 501/753] Storing BlockNumber & transactions directly in enum --- rpc/src/v1/helpers/poll_filter.rs | 9 +- rpc/src/v1/helpers/poll_manager.rs | 183 ++++++----------------------- rpc/src/v1/impls/eth.rs | 45 ++++--- 3 files changed, 59 insertions(+), 178 deletions(-) diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index 465290270..f9ed6230c 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -1,10 +1,13 @@ //! Helper type with all filter possibilities. +use util::hash::H256; use ethcore::filter::Filter; +pub type BlockNumber = u64; + #[derive(Clone)] pub enum PollFilter { - Block, - PendingTransaction, - Logs(Filter) + Block(BlockNumber), + PendingTransaction(Vec), + Logs(BlockNumber, Filter) } diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs index 765410567..9735d7d5d 100644 --- a/rpc/src/v1/helpers/poll_manager.rs +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -16,36 +16,18 @@ //! Indexes all rpc poll requests. -use util::hash::H256; -use std::collections::HashMap; use transient_hashmap::{TransientHashMap, Timer, StandardTimer}; /// Lifetime of poll (in seconds). const POLL_LIFETIME: u64 = 60; pub type PollId = usize; -pub type BlockNumber = u64; - -pub struct PollInfo { - pub filter: F, - pub block_number: BlockNumber -} - -impl Clone for PollInfo where F: Clone { - fn clone(&self) -> Self { - PollInfo { - filter: self.filter.clone(), - block_number: self.block_number.clone() - } - } -} /// Indexes all poll requests. /// /// Lazily garbage collects unused polls info. pub struct PollManager where T: Timer { - polls: TransientHashMap, T>, - transactions_data: HashMap>, + polls: TransientHashMap, next_available_id: PollId, } @@ -57,188 +39,89 @@ impl PollManager { } impl PollManager where T: Timer { + pub fn new_with_timer(timer: T) -> Self { PollManager { polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), - transactions_data: HashMap::new(), next_available_id: 0, } } - fn prune(&mut self) { - self.polls.prune(); - // self.polls.prune() - // .into_iter() - // .map(|key| { - // self.transactions_data.remove(key); - // }); - } - /// Returns id which can be used for new poll. /// /// Stores information when last poll happend. - pub fn create_poll(&mut self, filter: F, block: BlockNumber) -> PollId { - self.prune(); + pub fn create_poll(&mut self, filter: F) -> PollId { + self.polls.prune(); + let id = self.next_available_id; + self.polls.insert(id, filter); + self.next_available_id += 1; - self.polls.insert(id, PollInfo { - filter: filter, - block_number: block, - }); id } - /// Updates information when last poll happend. - pub fn update_poll(&mut self, id: &PollId, block: BlockNumber) { - self.prune(); - if let Some(info) = self.polls.get_mut(id) { - info.block_number = block; - } - } - - /// Returns number of block when last poll happend. - pub fn poll_info(&mut self, id: &PollId) -> Option<&PollInfo> { - self.prune(); + // Implementation is always using `poll_mut` + #[cfg(test)] + /// Get a reference to stored poll filter + pub fn poll(&mut self, id: &PollId) -> Option<&F> { + self.polls.prune(); self.polls.get(id) } - pub fn update_transactions(&mut self, id: &PollId, transactions: Vec) -> Option> { - self.prune(); - if self.polls.get(id).is_some() { - self.transactions_data.insert(*id, transactions) - } else { - None - } - } - - // Normal code always replaces transactions - #[cfg(test)] - /// Returns last transactions hashes for given poll. - pub fn transactions(&mut self, id: &PollId) -> Option<&Vec> { - self.prune(); - self.transactions_data.get(id) + /// Get a mutable reference to stored poll filter + pub fn poll_mut(&mut self, id: &PollId) -> Option<&mut F> { + self.polls.prune(); + self.polls.get_mut(id) } /// Removes poll info. pub fn remove_poll(&mut self, id: &PollId) { self.polls.remove(id); - self.transactions_data.remove(id); } } #[cfg(test)] mod tests { - use std::cell::RefCell; + use std::cell::Cell; use transient_hashmap::Timer; use v1::helpers::PollManager; - use util::hash::H256; struct TestTimer<'a> { - time: &'a RefCell, + time: &'a Cell, } impl<'a> Timer for TestTimer<'a> { fn get_time(&self) -> i64 { - *self.time.borrow() + self.time.get() } } #[test] fn test_poll_indexer() { - let time = RefCell::new(0); + let time = Cell::new(0); let timer = TestTimer { time: &time, }; let mut indexer = PollManager::new_with_timer(timer); - assert_eq!(indexer.create_poll(false, 20), 0); - assert_eq!(indexer.create_poll(true, 20), 1); + assert_eq!(indexer.create_poll(20), 0); + assert_eq!(indexer.create_poll(20), 1); - *time.borrow_mut() = 10; - indexer.update_poll(&0, 21); - assert_eq!(indexer.poll_info(&0).unwrap().filter, false); - assert_eq!(indexer.poll_info(&0).unwrap().block_number, 21); + time.set(10); + *indexer.poll_mut(&0).unwrap() = 21; + assert_eq!(*indexer.poll(&0).unwrap(), 21); + assert_eq!(*indexer.poll(&1).unwrap(), 20); - *time.borrow_mut() = 30; - indexer.update_poll(&1, 23); - assert_eq!(indexer.poll_info(&1).unwrap().filter, true); - assert_eq!(indexer.poll_info(&1).unwrap().block_number, 23); + time.set(30); + *indexer.poll_mut(&1).unwrap() = 23; + assert_eq!(*indexer.poll(&1).unwrap(), 23); - *time.borrow_mut() = 75; - indexer.update_poll(&0, 30); - assert!(indexer.poll_info(&0).is_none()); - assert_eq!(indexer.poll_info(&1).unwrap().filter, true); - assert_eq!(indexer.poll_info(&1).unwrap().block_number, 23); + time.set(75); + assert!(indexer.poll(&0).is_none()); + assert_eq!(*indexer.poll(&1).unwrap(), 23); indexer.remove_poll(&1); - assert!(indexer.poll_info(&1).is_none()); + assert!(indexer.poll(&1).is_none()); } - #[test] - fn should_return_poll_transactions_hashes() { - // given - let mut indexer = PollManager::new(); - let poll_id = indexer.create_poll(false, 20); - assert!(indexer.transactions(&poll_id).is_none()); - let transactions = vec![H256::from(1), H256::from(2)]; - - // when - indexer.update_transactions(&poll_id, transactions.clone()); - - // then - let txs = indexer.transactions(&poll_id); - assert_eq!(txs.unwrap(), &transactions); - } - - - #[test] - fn should_remove_transaction_data_when_poll_timed_out() { - // given - let time = RefCell::new(0); - let timer = TestTimer { - time: &time, - }; - let mut indexer = PollManager::new_with_timer(timer); - let poll_id = indexer.create_poll(false, 20); - let transactions = vec![H256::from(1), H256::from(2)]; - indexer.update_transactions(&poll_id, transactions.clone()); - assert!(indexer.transactions(&poll_id).is_some()); - - // when - *time.borrow_mut() = 75; - indexer.prune(); - - // then - assert!(indexer.transactions(&poll_id).is_none()); - - } - - #[test] - fn should_remove_transaction_data_when_poll_is_removed() { - // given - let mut indexer = PollManager::new(); - let poll_id = indexer.create_poll(false, 20); - let transactions = vec![H256::from(1), H256::from(2)]; - - // when - indexer.update_transactions(&poll_id, transactions.clone()); - assert!(indexer.transactions(&poll_id).is_some()); - indexer.remove_poll(&poll_id); - - // then - assert!(indexer.transactions(&poll_id).is_none()); - } - - #[test] - fn should_ignore_transactions_for_invalid_poll_id() { - // given - let mut indexer = PollManager::<()>::new(); - let transactions = vec![H256::from(1), H256::from(2)]; - - // when - indexer.update_transactions(&5, transactions.clone()); - - // then - assert!(indexer.transactions(&5).is_none()); - } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 211c46304..9f81caa90 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -301,7 +301,8 @@ impl EthFilter for EthFilterClient from_params::<(Filter,)>(params) .and_then(|(filter,)| { let mut polls = self.polls.lock().unwrap(); - let id = polls.create_poll(PollFilter::Logs(filter.into()), take_weak!(self.client).chain_info().best_block_number); + let block_number = take_weak!(self.client).chain_info().best_block_number; + let id = polls.create_poll(PollFilter::Logs(block_number, filter.into())); to_value(&U256::from(id)) }) } @@ -310,7 +311,7 @@ impl EthFilter for EthFilterClient match params { Params::None => { let mut polls = self.polls.lock().unwrap(); - let id = polls.create_poll(PollFilter::Block, take_weak!(self.client).chain_info().best_block_number); + let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); to_value(&U256::from(id)) }, _ => Err(Error::invalid_params()) @@ -321,11 +322,8 @@ impl EthFilter for EthFilterClient match params { Params::None => { let mut polls = self.polls.lock().unwrap(); - let best_block_number = take_weak!(self.client).chain_info().best_block_number; let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); - - let id = polls.create_poll(PollFilter::PendingTransaction, best_block_number); - polls.update_transactions(&id, pending_transactions); + let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); to_value(&U256::from(id)) }, @@ -337,50 +335,47 @@ impl EthFilter for EthFilterClient let client = take_weak!(self.client); from_params::<(Index,)>(params) .and_then(|(index,)| { - let info = self.polls.lock().unwrap().poll_info(&index.value()).cloned(); - match info { + let mut polls = self.polls.lock().unwrap(); + match polls.poll_mut(&index.value()) { None => Ok(Value::Array(vec![] as Vec)), - Some(info) => match info.filter { - PollFilter::Block => { + Some(filter) => match *filter { + PollFilter::Block(ref mut block_number) => { // + 1, cause we want to return hashes including current block hash. let current_number = client.chain_info().best_block_number + 1; - let hashes = (info.block_number..current_number).into_iter() + let hashes = (*block_number..current_number).into_iter() .map(BlockId::Number) .filter_map(|id| client.block_hash(id)) .collect::>(); - self.polls.lock().unwrap().update_poll(&index.value(), current_number); + *block_number = current_number; to_value(&hashes) }, - PollFilter::PendingTransaction => { - let poll_id = index.value(); - let mut polls = self.polls.lock().unwrap(); - + PollFilter::PendingTransaction(ref mut previous_hashes) => { let current_hashes = take_weak!(self.miner).pending_transactions_hashes(); - let previous_hashes = polls.update_transactions(&poll_id, current_hashes.clone()).unwrap(); - polls.update_poll(&poll_id, client.chain_info().best_block_number); - // calculate diff - let previous_hashes_set = previous_hashes.into_iter().collect::>(); + let previous_hashes_set = previous_hashes.into_iter().map(|h| h.clone()).collect::>(); let diff = current_hashes - .into_iter() + .iter() .filter(|hash| previous_hashes_set.contains(&hash)) + .cloned() .collect::>(); + *previous_hashes = current_hashes; + to_value(&diff) }, - PollFilter::Logs(mut filter) => { - filter.from_block = BlockId::Number(info.block_number); + PollFilter::Logs(ref mut block_number, ref mut filter) => { + filter.from_block = BlockId::Number(*block_number); filter.to_block = BlockId::Latest; - let logs = client.logs(filter) + let logs = client.logs(filter.clone()) .into_iter() .map(From::from) .collect::>(); let current_number = client.chain_info().best_block_number; - self.polls.lock().unwrap().update_poll(&index.value(), current_number); + *block_number = current_number; to_value(&logs) } } From 190630cc6bd3ed4d076f6b6490a431ee4b5180ec Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 12:31:45 +0100 Subject: [PATCH 502/753] separated transaction_request to its own submodule, added basic tests for it --- rpc/src/v1/impls/eth.rs | 3 +- rpc/src/v1/types/mod.rs.in | 3 +- rpc/src/v1/types/transaction.rs | 32 +------- rpc/src/v1/types/transaction_request.rs | 101 ++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 rpc/src/v1/types/transaction_request.rs diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 102d0da61..38e363624 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -27,6 +27,7 @@ use ethcore::block::{IsBlock}; use ethcore::views::*; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; +use ethcore::transaction::Transaction as EthTransaction; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; use v1::helpers::{PollFilter, PollManager}; @@ -274,7 +275,7 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: match accounts.account_secret(&transaction_request.from) { Ok(secret) => { let sync = take_weak!(self.sync); - let (transaction, _) = transaction_request.to_eth(); + let transaction: EthTransaction = transaction_request.into(); let signed_transaction = transaction.sign(&secret); let hash = signed_transaction.hash(); sync.insert_transaction(signed_transaction); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 2b2390ecb..ebc3bc0ff 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -23,6 +23,7 @@ mod log; mod optionals; mod sync; mod transaction; +mod transaction_request; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; @@ -33,5 +34,5 @@ pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; -pub use self::transaction::TransactionRequest; +pub use self::transaction_request::TransactionRequest; diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 17b42cfcf..0518a58ea 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -17,8 +17,7 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; -use serde::{Deserializer, Error}; -use ethcore; +use serde::Error; #[derive(Debug, Default, Serialize)] pub struct Transaction { @@ -39,35 +38,6 @@ pub struct Transaction { pub input: Bytes } -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct TransactionRequest { - pub from: Address, - pub to: Option
, - #[serde(rename="gasPrice")] - pub gas_price: Option, - pub gas: Option, - pub value: Option, - pub data: Bytes, - pub nonce: Option, -} - -impl TransactionRequest { - /// maps transaction request to the transaction that can be signed and inserted - pub fn to_eth(self) -> (ethcore::transaction::Transaction, Address) { - (ethcore::transaction::Transaction { - nonce: self.nonce.unwrap_or(U256::zero()), - action: match self.to { - None => ethcore::transaction::Action::Create, - Some(addr) => ethcore::transaction::Action::Call(addr) - }, - gas: self.gas.unwrap_or(U256::zero()), - gas_price: self.gas_price.unwrap_or(U256::zero()), - value: self.value.unwrap_or(U256::zero()), - data: self.data.to_vec() - }, self.from) - } -} - impl From for Transaction { fn from(t: LocalizedTransaction) -> Transaction { Transaction { diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs new file mode 100644 index 000000000..a61b11c25 --- /dev/null +++ b/rpc/src/v1/types/transaction_request.rs @@ -0,0 +1,101 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::hash::Address; +use util::numbers::{Uint, U256}; +use ethcore::transaction::{Action, Transaction}; +use v1::types::Bytes; + +#[derive(Debug, Default, Deserialize)] +pub struct TransactionRequest { + pub from: Address, + pub to: Option
, + #[serde(rename="gasPrice")] + pub gas_price: Option, + pub gas: Option, + pub value: Option, + pub data: Bytes, + pub nonce: Option, +} + +impl Into for TransactionRequest { + fn into(self) -> Transaction { + Transaction { + nonce: self.nonce.unwrap_or(U256::zero()), + action: match self.to { + None => Action::Create, + Some(addr) => Action::Call(addr) + }, + gas: self.gas.unwrap_or(U256::zero()), + gas_price: self.gas_price.unwrap_or(U256::zero()), + value: self.value.unwrap_or(U256::zero()), + data: self.data.to_vec() + } + } +} + +#[cfg(test)] +mod tests { + use util::numbers::{Uint, U256}; + use util::hash::Address; + use ethcore::transaction::{Transaction, Action}; + use v1::types::Bytes; + use super::*; + + #[test] + fn transaction_request_into_transaction() { + let tr = TransactionRequest { + from: Address::default(), + to: Some(Address::from(10)), + gas_price: Some(U256::from(20)), + gas: Some(U256::from(10_000)), + value: Some(U256::from(1)), + data: Bytes::new(vec![10, 20]), + nonce: Some(U256::from(12)), + }; + + assert_eq!(Transaction { + nonce: U256::from(12), + action: Action::Call(Address::from(10)), + gas: U256::from(10_000), + gas_price: U256::from(20), + value: U256::from(1), + data: vec![10, 20], + }, tr.into()); + } + + #[test] + fn empty_transaction_request_into_transaction() { + let tr = TransactionRequest { + from: Address::default(), + to: None, + gas_price: None, + gas: None, + value: None, + data: Bytes::new(vec![]), + nonce: None, + }; + + assert_eq!(Transaction { + nonce: U256::zero(), + action: Action::Create, + gas: U256::zero(), + gas_price: U256::zero(), + value: U256::zero(), + data: vec![], + }, tr.into()); + } +} From ed0047725cbe4a027bd6c75bf592728cf1292efb Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 15:49:49 +0400 Subject: [PATCH 503/753] adding cli extension --- parity/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index b6ed5cba3..5f6d50027 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -101,7 +101,7 @@ API and Console Options: --jsonrpc-port PORT Specify the port portion of the JSONRPC API server [default: 8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. --jsonrpc-apis APIS Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited - list of API name. Possible name are web3, eth and net. [default: web3,eth,net]. + list of API name. Possible name are web3, eth and net. [default: web3,eth,net,personal]. --rpc Equivalent to --jsonrpc (geth-compatible). --rpcaddr HOST Equivalent to --jsonrpc-addr HOST (geth-compatible). --rpcport PORT Equivalent to --jsonrpc-port PORT (geth-compatible). @@ -208,6 +208,7 @@ fn setup_rpc_server(client: Arc, sync: Arc, secret_store: Arc server.add_delegate(PersonalClient::new(&secret_store).to_delegate()), _ => { die!("{}: Invalid API name to be enabled.", api); } From 70ee6aa94219bac3cc22dbc9dac037b76e535c15 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 15:50:13 +0400 Subject: [PATCH 504/753] refactoring to use generic account provider as web3 svc --- rpc/src/v1/impls/personal.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 7b79ceae7..ce200244c 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -22,20 +22,20 @@ use util::keys::store::*; use util::Address; /// Account management (personal) rpc implementation. -pub struct PersonalClient { - accounts: Weak, +pub struct PersonalClient where A: AccountProvider { + accounts: Weak, } -impl PersonalClient { +impl PersonalClient where A: AccountProvider { /// Creates new PersonalClient - pub fn new(store: &Arc) -> Self { + pub fn new(store: &Arc) -> Self { PersonalClient { accounts: Arc::downgrade(store), } } } -impl Personal for PersonalClient { +impl Personal for PersonalClient where A: AccountProvider + 'static { fn accounts(&self, _: Params) -> Result { let store = take_weak!(self.accounts); match store.accounts() { From 756f96413045e63a3dccf801f992c46ed22f7dfb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 12:54:48 +0100 Subject: [PATCH 505/753] JournalDB -> Box, and it's a trait. --- ethcore/src/block.rs | 16 ++--- ethcore/src/client.rs | 12 ++-- ethcore/src/state.rs | 26 +++---- ethcore/src/tests/helpers.rs | 8 +-- util/src/hashdb.rs | 15 ++++- util/src/journaldb.rs | 127 +++++++++++++++++++---------------- util/src/overlaydb.rs | 1 + 7 files changed, 116 insertions(+), 89 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index b3894db94..ea9e91781 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -171,7 +171,7 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new(engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { + pub fn new(engine: &'x Engine, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { let mut r = OpenBlock { block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), engine: engine, @@ -317,7 +317,7 @@ impl ClosedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> JournalDB { self.block.state.drop().1 } + pub fn drain(self) -> Box { self.block.state.drop().1 } } impl SealedBlock { @@ -331,7 +331,7 @@ impl SealedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> JournalDB { self.block.state.drop().1 } + pub fn drain(self) -> Box { self.block.state.drop().1 } } impl IsBlock for SealedBlock { @@ -339,10 +339,10 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { - let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce()); + let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce()); trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author())); } } @@ -357,20 +357,20 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let view = BlockView::new(&block.bytes); enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal()))) } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index b342cef15..7ccf094d2 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -214,7 +214,7 @@ impl ClientReport { pub struct Client where V: Verifier { chain: Arc>, engine: Arc>, - state_db: Mutex, + state_db: Mutex>, block_queue: RwLock, report: RwLock, import_lock: Mutex<()>, @@ -253,8 +253,8 @@ impl Client where V: Verifier { state_path.push("state"); let engine = Arc::new(try!(spec.to_engine())); - let mut state_db = JournalDB::from_prefs(state_path.to_str().unwrap(), config.prefer_journal); - if state_db.is_empty() && engine.spec().ensure_db_good(&mut state_db) { + let mut state_db = Box::new(OptionOneDB::from_prefs(state_path.to_str().unwrap(), config.prefer_journal)); + if state_db.is_empty() && engine.spec().ensure_db_good(state_db.deref_mut()) { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); } @@ -336,7 +336,7 @@ impl Client where V: Verifier { // Enact Verified Block let parent = chain_has_parent.unwrap(); let last_hashes = self.build_last_hashes(header.parent_hash.clone()); - let db = self.state_db.lock().unwrap().clone(); + let db = self.state_db.lock().unwrap().spawn(); let enact_result = enact_verified(&block, engine, db, &parent, last_hashes); if let Err(e) = enact_result { @@ -438,7 +438,7 @@ impl Client where V: Verifier { /// Get a copy of the best block's state. pub fn state(&self) -> State { - State::from_existing(self.state_db.lock().unwrap().clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce()) + State::from_existing(self.state_db.lock().unwrap().spawn(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce()) } /// Get info on the cache. @@ -507,7 +507,7 @@ impl Client where V: Verifier { let h = self.chain.read().unwrap().best_block_hash(); let mut b = OpenBlock::new( self.engine.deref().deref(), - self.state_db.lock().unwrap().clone(), + self.state_db.lock().unwrap().spawn(), match self.chain.read().unwrap().block_header(&h) { Some(ref x) => x, None => {return;} }, self.build_last_hashes(h.clone()), self.author(), diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 7c1064abf..9a3d1791d 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -31,7 +31,7 @@ pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. pub struct State { - db: JournalDB, + db: Box, root: H256, cache: RefCell>>, snapshots: RefCell>>>>, @@ -41,11 +41,11 @@ pub struct State { impl State { /// Creates new state with empty state root #[cfg(test)] - pub fn new(mut db: JournalDB, account_start_nonce: U256) -> State { + pub fn new(mut db: Box, account_start_nonce: U256) -> State { let mut root = H256::new(); { // init trie and reset root too null - let _ = SecTrieDBMut::new(&mut db, &mut root); + let _ = SecTrieDBMut::new(db.deref_mut(), &mut root); } State { @@ -58,10 +58,10 @@ impl State { } /// Creates new state with existing state root - pub fn from_existing(db: JournalDB, root: H256, account_start_nonce: U256) -> State { + pub fn from_existing(db: Box, root: H256, account_start_nonce: U256) -> State { { // trie should panic! if root does not exist - let _ = SecTrieDB::new(&db, &root); + let _ = SecTrieDB::new(db.as_hashdb(), &root); } State { @@ -126,7 +126,7 @@ impl State { } /// Destroy the current object and return root and database. - pub fn drop(self) -> (H256, JournalDB) { + pub fn drop(self) -> (H256, Box) { (self.root, self.db) } @@ -148,7 +148,7 @@ impl State { /// Determine whether an account exists. pub fn exists(&self, a: &Address) -> bool { - self.cache.borrow().get(&a).unwrap_or(&None).is_some() || SecTrieDB::new(&self.db, &self.root).contains(&a) + self.cache.borrow().get(&a).unwrap_or(&None).is_some() || SecTrieDB::new(self.db.as_hashdb(), &self.root).contains(&a) } /// Get the balance of account `a`. @@ -163,7 +163,7 @@ impl State { /// Mutate storage of account `address` so that it is `value` for `key`. pub fn storage_at(&self, address: &Address, key: &H256) -> H256 { - self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(&self.db, address), key)) + self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(self.db.as_hashdb(), address), key)) } /// Mutate storage of account `a` so that it is `value` for `key`. @@ -253,7 +253,7 @@ impl State { /// Commits our cached account changes into the trie. pub fn commit(&mut self) { assert!(self.snapshots.borrow().is_empty()); - Self::commit_into(&mut self.db, &mut self.root, self.cache.borrow_mut().deref_mut()); + Self::commit_into(self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut()); } #[cfg(test)] @@ -285,11 +285,11 @@ impl State { fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option { let have_key = self.cache.borrow().contains_key(a); if !have_key { - self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(Account::from_rlp)) + self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp)) } if require_code { if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() { - account.cache_code(&AccountDB::new(&self.db, a)); + account.cache_code(&AccountDB::new(self.db.as_hashdb(), a)); } } unsafe { ::std::mem::transmute(self.cache.borrow().get(a).unwrap()) } @@ -305,7 +305,7 @@ impl State { fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account { let have_key = self.cache.borrow().contains_key(a); if !have_key { - self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(Account::from_rlp)) + self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp)) } else { self.note_cache(a); } @@ -318,7 +318,7 @@ impl State { unsafe { ::std::mem::transmute(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().map(|account| { if require_code { - account.cache_code(&AccountDB::new(&self.db, a)); + account.cache_code(&AccountDB::new(self.db.as_hashdb(), a)); } account }).unwrap()) } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index bb9a44614..7b99f68d5 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -250,9 +250,9 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { } } -pub fn get_temp_journal_db() -> GuardedTempResult { +pub fn get_temp_journal_db() -> GuardedTempResult> { let temp = RandomTempPath::new(); - let journal_db = JournalDB::new(temp.as_str()); + let journal_db = Box::new(OptionOneDB::new(temp.as_str())); GuardedTempResult { _temp: temp, result: Some(journal_db) @@ -268,8 +268,8 @@ pub fn get_temp_state() -> GuardedTempResult { } } -pub fn get_temp_journal_db_in(path: &Path) -> JournalDB { - JournalDB::new(path.to_str().unwrap()) +pub fn get_temp_journal_db_in(path: &Path) -> Box { + Box::new(OptionOneDB::new(path.to_str().unwrap())) } pub fn get_temp_state_in(path: &Path) -> State { diff --git a/util/src/hashdb.rs b/util/src/hashdb.rs index 4d8cbaba1..e622c4b99 100644 --- a/util/src/hashdb.rs +++ b/util/src/hashdb.rs @@ -20,7 +20,7 @@ use bytes::*; use std::collections::HashMap; /// Trait modelling datastore keyed by a 32-byte Keccak hash. -pub trait HashDB { +pub trait HashDB : AsHashDB { /// Get the keys in the database together with number of underlying references. fn keys(&self) -> HashMap; @@ -111,3 +111,16 @@ pub trait HashDB { /// ``` fn remove(&mut self, key: &H256) { self.kill(key) } } + +/// Upcast trait. +pub trait AsHashDB { + /// Perform upcast to HashDB for anything that derives from HashDB. + fn as_hashdb(&self) -> &HashDB; + /// Perform mutable upcast to HashDB for anything that derives from HashDB. + fn as_hashdb_mut(&mut self) -> &mut HashDB; +} + +impl AsHashDB for T { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 35ad83fa0..23fd08011 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -24,6 +24,22 @@ use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; +/// A HashDB which can manage a short-term journal potentially containing many forks of mutually +/// exclusive actions. +pub trait JournalDB : HashDB { + /// Return a copy of ourself, in a box. + fn spawn(&self) -> Box; + + /// Returns heap memory size used + fn mem_used(&self) -> usize; + + /// Check if this database has any commits + fn is_empty(&self) -> bool; + + /// Commit all recent insert operations. + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result; +} + /// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// @@ -31,22 +47,12 @@ use std::env; /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. -pub struct JournalDB { +pub struct OptionOneDB { overlay: MemoryDB, backing: Arc, counters: Option>>>, } -impl Clone for JournalDB { - fn clone(&self) -> JournalDB { - JournalDB { - overlay: MemoryDB::new(), - backing: self.backing.clone(), - counters: self.counters.clone(), - } - } -} - // all keys must be at least 12 bytes const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; @@ -56,14 +62,14 @@ const DB_VERSION_NO_JOURNAL : u32 = 3 + 256; const PADDING : [u8; 10] = [ 0u8; 10 ]; -impl JournalDB { +impl OptionOneDB { /// Create a new instance from file - pub fn new(path: &str) -> JournalDB { + pub fn new(path: &str) -> OptionOneDB { Self::from_prefs(path, true) } /// Create a new instance from file - pub fn from_prefs(path: &str, prefer_journal: bool) -> JournalDB { + pub fn from_prefs(path: &str, prefer_journal: bool) -> OptionOneDB { let opts = DatabaseConfig { prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix }; @@ -83,11 +89,11 @@ impl JournalDB { } let counters = if with_journal { - Some(Arc::new(RwLock::new(JournalDB::read_counters(&backing)))) + Some(Arc::new(RwLock::new(OptionOneDB::read_counters(&backing)))) } else { None }; - JournalDB { + OptionOneDB { overlay: MemoryDB::new(), backing: Arc::new(backing), counters: counters, @@ -96,27 +102,12 @@ impl JournalDB { /// Create a new instance with an anonymous temporary database. #[cfg(test)] - pub fn new_temp() -> JournalDB { + fn new_temp() -> OptionOneDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); Self::new(dir.to_str().unwrap()) } - /// Check if this database has any commits - pub fn is_empty(&self) -> bool { - self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() - } - - /// Commit all recent insert operations. - pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - let have_counters = self.counters.is_some(); - if have_counters { - self.commit_with_counters(now, id, end) - } else { - self.commit_without_counters() - } - } - /// Drain the overlay and place it into a batch for the DB. fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> usize { let mut inserts = 0usize; @@ -339,11 +330,11 @@ impl JournalDB { try!(batch.delete(&last)); index += 1; } - trace!("JournalDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); + trace!("OptionOneDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); } try!(self.backing.write(batch)); -// trace!("JournalDB::commit() deleted {} nodes", deletes); +// trace!("OptionOneDB::commit() deleted {} nodes", deletes); Ok(0) } @@ -379,17 +370,9 @@ impl JournalDB { trace!("Recovered {} counters", counters.len()); counters } +} - /// Returns heap memory size used - pub fn mem_used(&self) -> usize { - self.overlay.mem_used() + match self.counters { - Some(ref c) => c.read().unwrap().heap_size_of_children(), - None => 0 - } - } - } - -impl HashDB for JournalDB { +impl HashDB for OptionOneDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter() { @@ -434,6 +417,36 @@ impl HashDB for JournalDB { } } +impl JournalDB for OptionOneDB { + fn spawn(&self) -> Box { + Box::new(OptionOneDB { + overlay: MemoryDB::new(), + backing: self.backing.clone(), + counters: self.counters.clone(), + }) + } + + fn mem_used(&self) -> usize { + self.overlay.mem_used() + match self.counters { + Some(ref c) => c.read().unwrap().heap_size_of_children(), + None => 0 + } + } + + fn is_empty(&self) -> bool { + self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + } + + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + let have_counters = self.counters.is_some(); + if have_counters { + self.commit_with_counters(now, id, end) + } else { + self.commit_without_counters() + } + } +} + #[cfg(test)] mod tests { use common::*; @@ -443,7 +456,7 @@ mod tests { #[test] fn insert_same_in_fork() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let x = jdb.insert(b"X"); jdb.commit(1, &b"1".sha3(), None).unwrap(); @@ -465,7 +478,7 @@ mod tests { #[test] fn long_history() { // history is 3 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let h = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.exists(&h)); @@ -483,7 +496,7 @@ mod tests { #[test] fn complex() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -521,7 +534,7 @@ mod tests { #[test] fn fork() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -549,7 +562,7 @@ mod tests { #[test] fn overwrite() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -568,7 +581,7 @@ mod tests { #[test] fn fork_same_key() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); jdb.commit(0, &b"0".sha3(), None).unwrap(); let foo = jdb.insert(b"foo"); @@ -590,7 +603,7 @@ mod tests { let bar = H256::random(); let foo = { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.emplace(bar.clone(), b"bar".to_vec()); @@ -599,13 +612,13 @@ mod tests { }; { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); } { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); @@ -619,7 +632,7 @@ mod tests { dir.push(H32::random().hex()); let foo = { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -633,7 +646,7 @@ mod tests { }; { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); assert!(jdb.exists(&foo)); @@ -648,7 +661,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); let (foo, bar, baz) = { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -663,7 +676,7 @@ mod tests { }; { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&baz)); diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index 3c80f4148..f14677d05 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -36,6 +36,7 @@ use kvdb::{Database}; /// /// `lookup()` and `contains()` maintain normal behaviour - all `insert()` and `remove()` /// queries have an immediate effect in terms of these functions. +#[derive(Clone)] pub struct OverlayDB { overlay: MemoryDB, backing: Arc, From 99c5794929e0c14b524f949fcc16a5ecbda88fee Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 16:00:30 +0400 Subject: [PATCH 506/753] fix warning for transaction_queue.add usage --- sync/src/chain.rs | 4 ++-- sync/src/lib.rs | 3 ++- sync/src/transaction_queue.rs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 866838bec..d65685dfe 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1306,11 +1306,11 @@ impl ChainSync { } /// Add transaction to the transaction queue - pub fn insert_transaction(&self, transaction: ethcore::transaction::SignedTransaction, fetch_nonce: &T) + pub fn insert_transaction(&self, transaction: ethcore::transaction::SignedTransaction, fetch_nonce: &T) -> Result<(), Error> where T: Fn(&Address) -> U256 { let mut queue = self.transaction_queue.lock().unwrap(); - queue.add(transaction, fetch_nonce); + queue.add(transaction, fetch_nonce) } } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 3b79e5614..a416c8829 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -146,7 +146,8 @@ impl SyncProvider for EthSync { let nonce_fn = |a: &Address| self.chain.state().nonce(a) + U256::one(); let sync = self.sync.write().unwrap(); - sync.insert_transaction(transaction, &nonce_fn); + sync.insert_transaction(transaction, &nonce_fn).unwrap_or_else( + |e| warn!(target: "sync", "Error inserting transaction to queue: {:?}", e)); } } diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 243939a4c..618eb6a0b 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -684,8 +684,8 @@ mod test { let mut txq = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(1)); - txq.add(tx.clone(), &prev_nonce); - txq.add(tx2.clone(), &prev_nonce); + txq.add(tx.clone(), &prev_nonce).unwrap(); + txq.add(tx2.clone(), &prev_nonce).unwrap(); assert_eq!(txq.status().future, 2); // when From d71c5d4c17f26484fb15511d155e02f7a27eab3b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 13:19:10 +0100 Subject: [PATCH 507/753] Place Sync/Send in trait. --- ethcore/src/block.rs | 14 +++++++------- ethcore/src/client/client.rs | 2 +- ethcore/src/state.rs | 8 ++++---- ethcore/src/tests/helpers.rs | 4 ++-- util/src/journaldb.rs | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index ea9e91781..ab5086273 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -171,7 +171,7 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new(engine: &'x Engine, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { + pub fn new(engine: &'x Engine, db: Box>, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { let mut r = OpenBlock { block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), engine: engine, @@ -317,7 +317,7 @@ impl ClosedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> Box { self.block.state.drop().1 } + pub fn drain(self) -> Box> { self.block.state.drop().1 } } impl SealedBlock { @@ -331,7 +331,7 @@ impl SealedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> Box { self.block.state.drop().1 } + pub fn drain(self) -> Box> { self.block.state.drop().1 } } impl IsBlock for SealedBlock { @@ -339,7 +339,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce()); @@ -357,20 +357,20 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { let view = BlockView::new(&block.bytes); enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal()))) } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index e2fe7bb90..ea0919bcc 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -101,7 +101,7 @@ impl ClientReport { pub struct Client where V: Verifier { chain: Arc, engine: Arc>, - state_db: Mutex>, + state_db: Mutex>>, block_queue: BlockQueue, report: RwLock, import_lock: Mutex<()>, diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 9a3d1791d..222b88643 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -31,7 +31,7 @@ pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. pub struct State { - db: Box, + db: Box>, root: H256, cache: RefCell>>, snapshots: RefCell>>>>, @@ -41,7 +41,7 @@ pub struct State { impl State { /// Creates new state with empty state root #[cfg(test)] - pub fn new(mut db: Box, account_start_nonce: U256) -> State { + pub fn new(mut db: Box>, account_start_nonce: U256) -> State { let mut root = H256::new(); { // init trie and reset root too null @@ -58,7 +58,7 @@ impl State { } /// Creates new state with existing state root - pub fn from_existing(db: Box, root: H256, account_start_nonce: U256) -> State { + pub fn from_existing(db: Box>, root: H256, account_start_nonce: U256) -> State { { // trie should panic! if root does not exist let _ = SecTrieDB::new(db.as_hashdb(), &root); @@ -126,7 +126,7 @@ impl State { } /// Destroy the current object and return root and database. - pub fn drop(self) -> (H256, Box) { + pub fn drop(self) -> (H256, Box>) { (self.root, self.db) } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 7b99f68d5..85e311e82 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -250,7 +250,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { } } -pub fn get_temp_journal_db() -> GuardedTempResult> { +pub fn get_temp_journal_db() -> GuardedTempResult>> { let temp = RandomTempPath::new(); let journal_db = Box::new(OptionOneDB::new(temp.as_str())); GuardedTempResult { @@ -268,7 +268,7 @@ pub fn get_temp_state() -> GuardedTempResult { } } -pub fn get_temp_journal_db_in(path: &Path) -> Box { +pub fn get_temp_journal_db_in(path: &Path) -> Box> { Box::new(OptionOneDB::new(path.to_str().unwrap())) } diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 23fd08011..c6243ace0 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -26,9 +26,9 @@ use std::env; /// A HashDB which can manage a short-term journal potentially containing many forks of mutually /// exclusive actions. -pub trait JournalDB : HashDB { +pub trait JournalDB : HashDB + Sync + Send { /// Return a copy of ourself, in a box. - fn spawn(&self) -> Box; + fn spawn(&self) -> Box>; /// Returns heap memory size used fn mem_used(&self) -> usize; @@ -418,7 +418,7 @@ impl HashDB for OptionOneDB { } impl JournalDB for OptionOneDB { - fn spawn(&self) -> Box { + fn spawn(&self) -> Box> { Box::new(OptionOneDB { overlay: MemoryDB::new(), backing: self.backing.clone(), From 2a856a13f04271fbe78576858aedca3b2c4b659c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 13:21:53 +0100 Subject: [PATCH 508/753] Obvious typo fix. --- ethcore/src/block.rs | 14 +++++++------- ethcore/src/client/client.rs | 2 +- ethcore/src/state.rs | 8 ++++---- ethcore/src/tests/helpers.rs | 4 ++-- util/src/journaldb.rs | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index ab5086273..f3a4feaf0 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -171,7 +171,7 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new(engine: &'x Engine, db: Box>, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { + pub fn new(engine: &'x Engine, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { let mut r = OpenBlock { block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), engine: engine, @@ -317,7 +317,7 @@ impl ClosedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> Box> { self.block.state.drop().1 } + pub fn drain(self) -> Box { self.block.state.drop().1 } } impl SealedBlock { @@ -331,7 +331,7 @@ impl SealedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> Box> { self.block.state.drop().1 } + pub fn drain(self) -> Box { self.block.state.drop().1 } } impl IsBlock for SealedBlock { @@ -339,7 +339,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce()); @@ -357,20 +357,20 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let view = BlockView::new(&block.bytes); enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box>, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal()))) } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ea0919bcc..3c8a28380 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -101,7 +101,7 @@ impl ClientReport { pub struct Client where V: Verifier { chain: Arc, engine: Arc>, - state_db: Mutex>>, + state_db: Mutex>, block_queue: BlockQueue, report: RwLock, import_lock: Mutex<()>, diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 222b88643..519debcc1 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -31,7 +31,7 @@ pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. pub struct State { - db: Box>, + db: Box, root: H256, cache: RefCell>>, snapshots: RefCell>>>>, @@ -41,7 +41,7 @@ pub struct State { impl State { /// Creates new state with empty state root #[cfg(test)] - pub fn new(mut db: Box>, account_start_nonce: U256) -> State { + pub fn new(mut db: Box, account_start_nonce: U256) -> State { let mut root = H256::new(); { // init trie and reset root too null @@ -58,7 +58,7 @@ impl State { } /// Creates new state with existing state root - pub fn from_existing(db: Box>, root: H256, account_start_nonce: U256) -> State { + pub fn from_existing(db: Box, root: H256, account_start_nonce: U256) -> State { { // trie should panic! if root does not exist let _ = SecTrieDB::new(db.as_hashdb(), &root); @@ -126,7 +126,7 @@ impl State { } /// Destroy the current object and return root and database. - pub fn drop(self) -> (H256, Box>) { + pub fn drop(self) -> (H256, Box) { (self.root, self.db) } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 85e311e82..0bb6b5015 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -250,7 +250,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { } } -pub fn get_temp_journal_db() -> GuardedTempResult>> { +pub fn get_temp_journal_db() -> GuardedTempResult> { let temp = RandomTempPath::new(); let journal_db = Box::new(OptionOneDB::new(temp.as_str())); GuardedTempResult { @@ -268,7 +268,7 @@ pub fn get_temp_state() -> GuardedTempResult { } } -pub fn get_temp_journal_db_in(path: &Path) -> Box> { +pub fn get_temp_journal_db_in(path: &Path) -> Box { Box::new(OptionOneDB::new(path.to_str().unwrap())) } diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index c6243ace0..e7a670a08 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -28,7 +28,7 @@ use std::env; /// exclusive actions. pub trait JournalDB : HashDB + Sync + Send { /// Return a copy of ourself, in a box. - fn spawn(&self) -> Box>; + fn spawn(&self) -> Box; /// Returns heap memory size used fn mem_used(&self) -> usize; @@ -418,7 +418,7 @@ impl HashDB for OptionOneDB { } impl JournalDB for OptionOneDB { - fn spawn(&self) -> Box> { + fn spawn(&self) -> Box { Box::new(OptionOneDB { overlay: MemoryDB::new(), backing: self.backing.clone(), From 4771fdf0fb448d72e3b386dee78b308cd40f1c45 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 13:50:39 +0100 Subject: [PATCH 509/753] Rearrange journaldb infrastructure. --- ethcore/src/block_queue.rs | 1 + ethcore/src/client/client.rs | 10 +- util/src/journaldb/archivedb.rs | 387 ++++++++++++++++++ util/src/journaldb/mod.rs | 33 ++ .../optiononedb.rs} | 279 +++++-------- util/src/journaldb/traits.rs | 37 ++ 6 files changed, 571 insertions(+), 176 deletions(-) create mode 100644 util/src/journaldb/archivedb.rs create mode 100644 util/src/journaldb/mod.rs rename util/src/{journaldb.rs => journaldb/optiononedb.rs} (88%) create mode 100644 util/src/journaldb/traits.rs diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 4e335f705..8b7143b0b 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -412,6 +412,7 @@ impl BlockQueue { } } + /// Optimise memory footprint of the heap fields. pub fn collect_garbage(&self) { { self.verification.unverified.lock().unwrap().shrink_to_fit(); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 3c8a28380..70a3eb92a 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -139,8 +139,14 @@ impl Client where V: Verifier { state_path.push("state"); let engine = Arc::new(try!(spec.to_engine())); - let mut state_db = Box::new(OptionOneDB::from_prefs(state_path.to_str().unwrap(), config.prefer_journal)); - if state_db.is_empty() && engine.spec().ensure_db_good(state_db.deref_mut()) { + let state_path_str = state_path.to_str().unwrap(); + let mut state_db = if config.prefer_journal { + new_optiononedb(state_path_str) + } else { + new_archivedb(state_path_str) + }; + + if state_db.is_empty() && engine.spec().ensure_db_good(state_db.as_hashdb_mut()) { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); } diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs new file mode 100644 index 000000000..28cc4130a --- /dev/null +++ b/util/src/journaldb/archivedb.rs @@ -0,0 +1,387 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Disk-backed HashDB implementation. + +use common::*; +use rlp::*; +use hashdb::*; +use memorydb::*; +use super::traits::JournalDB; +use kvdb::{Database, DBTransaction, DatabaseConfig}; +#[cfg(test)] +use std::env; + +/// Implementation of the HashDB trait for a disk-backed database with a memory overlay +/// and latent-removal semantics. +/// +/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to +/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect +/// immediately. Rather some age (based on a linear but arbitrary metric) must pass before +/// the removals actually take effect. +pub struct ArchiveDB { + overlay: MemoryDB, + backing: Arc, +} + +// all keys must be at least 12 bytes +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const DB_VERSION : u32 = 259; + +impl ArchiveDB { + /// Create a new instance from file + pub fn new(path: &str) -> ArchiveDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(&opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + if !backing.is_empty() { + match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { + Ok(Some(DB_VERSION)) => {}, + v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) + } + } else { + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + } + + ArchiveDB { + overlay: MemoryDB::new(), + backing: Arc::new(backing), + } + } + + /// Create a new instance with an anonymous temporary database. + #[cfg(test)] + fn new_temp() -> ArchiveDB { + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + Self::new(dir.to_str().unwrap()) + } + + fn payload(&self, key: &H256) -> Option { + self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) + } +} + +impl HashDB for ArchiveDB { + fn keys(&self) -> HashMap { + let mut ret: HashMap = HashMap::new(); + for (key, _) in self.backing.iter() { + let h = H256::from_slice(key.deref()); + ret.insert(h, 1); + } + + for (key, refs) in self.overlay.keys().into_iter() { + let refs = *ret.get(&key).unwrap_or(&0) + refs; + ret.insert(key, refs); + } + ret + } + + fn lookup(&self, key: &H256) -> Option<&[u8]> { + let k = self.overlay.raw(key); + match k { + Some(&(ref d, rc)) if rc > 0 => Some(d), + _ => { + if let Some(x) = self.payload(key) { + Some(&self.overlay.denote(key, x).0) + } + else { + None + } + } + } + } + + fn exists(&self, key: &H256) -> bool { + self.lookup(key).is_some() + } + + fn insert(&mut self, value: &[u8]) -> H256 { + self.overlay.insert(value) + } + fn emplace(&mut self, key: H256, value: Bytes) { + self.overlay.emplace(key, value); + } + fn kill(&mut self, key: &H256) { + self.overlay.kill(key); + } +} + +impl JournalDB for ArchiveDB { + fn spawn(&self) -> Box { + Box::new(ArchiveDB { + overlay: MemoryDB::new(), + backing: self.backing.clone(), + }) + } + + fn mem_used(&self) -> usize { + self.overlay.mem_used() + } + + fn is_empty(&self) -> bool { + self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + } + + fn commit(&mut self, _: u64, _: &H256, _: Option<(u64, H256)>) -> Result { + let batch = DBTransaction::new(); + let mut inserts = 0usize; + let mut deletes = 0usize; + for i in self.overlay.drain().into_iter() { + let (key, (value, rc)) = i; + if rc > 0 { + assert!(rc == 1); + batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); + inserts += 1; + } + if rc < 0 { + assert!(rc == -1); + deletes += 1; + } + } + try!(self.backing.write(batch)); + Ok((inserts + deletes) as u32) + } +} + +#[cfg(test)] +mod tests { + use common::*; + use super::*; + use hashdb::*; + + #[test] + fn insert_same_in_fork() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let x = jdb.insert(b"X"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + jdb.commit(3, &b"1002a".sha3(), Some((1, b"1".sha3()))).unwrap(); + jdb.commit(4, &b"1003a".sha3(), Some((2, b"2".sha3()))).unwrap(); + + jdb.remove(&x); + jdb.commit(3, &b"1002b".sha3(), Some((1, b"1".sha3()))).unwrap(); + let x = jdb.insert(b"X"); + jdb.commit(4, &b"1003b".sha3(), Some((2, b"2".sha3()))).unwrap(); + + jdb.commit(5, &b"1004a".sha3(), Some((3, b"1002a".sha3()))).unwrap(); + jdb.commit(6, &b"1005a".sha3(), Some((4, b"1003a".sha3()))).unwrap(); + + assert!(jdb.exists(&x)); + } + + #[test] + fn long_history() { + // history is 3 + let mut jdb = ArchiveDB::new_temp(); + let h = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.remove(&h); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + } + + #[test] + fn complex() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + jdb.remove(&bar); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + let foo = jdb.insert(b"foo"); + jdb.remove(&baz); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&baz)); + + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + } + + #[test] + fn fork() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + + #[test] + fn overwrite() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + jdb.insert(b"foo"); + assert!(jdb.exists(&foo)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + jdb.commit(3, &b"2".sha3(), Some((0, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_same_key() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + + + #[test] + fn reopen() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let bar = H256::random(); + + let foo = { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.emplace(bar.clone(), b"bar".to_vec()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + foo + }; + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + } + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + } + } + + #[test] + fn reopen_remove() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let foo = { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + + // foo is ancient history. + + jdb.insert(b"foo"); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + foo + }; + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + } + } + #[test] + fn reopen_fork() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let (foo, bar, baz) = { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + (foo, bar, baz) + }; + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + } +} diff --git a/util/src/journaldb/mod.rs b/util/src/journaldb/mod.rs new file mode 100644 index 000000000..fdb825d51 --- /dev/null +++ b/util/src/journaldb/mod.rs @@ -0,0 +1,33 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! JournalDB interface and implementation. + +use common::*; + +/// Export the journaldb module. +pub mod traits; +mod archivedb; +mod optiononedb; + +/// Export the JournalDB trait. +pub use self::traits::JournalDB; + +/// Create a new JournalDB trait object which is an ArchiveDB. +pub fn new_archivedb(path: &str) -> Box { Box::new(archivedb::ArchiveDB::new(path)) } + +/// Create a new JournalDB trait object which is an OptionOneDB. +pub fn new_optiononedb(path: &str) -> Box { Box::new(optiononedb::OptionOneDB::new(path)) } diff --git a/util/src/journaldb.rs b/util/src/journaldb/optiononedb.rs similarity index 88% rename from util/src/journaldb.rs rename to util/src/journaldb/optiononedb.rs index e7a670a08..58bb88277 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb/optiononedb.rs @@ -20,26 +20,11 @@ use common::*; use rlp::*; use hashdb::*; use memorydb::*; +use super::traits::JournalDB; use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; -/// A HashDB which can manage a short-term journal potentially containing many forks of mutually -/// exclusive actions. -pub trait JournalDB : HashDB + Sync + Send { - /// Return a copy of ourself, in a box. - fn spawn(&self) -> Box; - - /// Returns heap memory size used - fn mem_used(&self) -> usize; - - /// Check if this database has any commits - fn is_empty(&self) -> bool; - - /// Commit all recent insert operations. - fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result; -} - /// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// @@ -56,43 +41,28 @@ pub struct OptionOneDB { // all keys must be at least 12 bytes const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; - const DB_VERSION : u32 = 3; -const DB_VERSION_NO_JOURNAL : u32 = 3 + 256; - const PADDING : [u8; 10] = [ 0u8; 10 ]; impl OptionOneDB { /// Create a new instance from file pub fn new(path: &str) -> OptionOneDB { - Self::from_prefs(path, true) - } - - /// Create a new instance from file - pub fn from_prefs(path: &str, prefer_journal: bool) -> OptionOneDB { let opts = DatabaseConfig { prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix }; let backing = Database::open(&opts, path).unwrap_or_else(|e| { panic!("Error opening state db: {}", e); }); - let with_journal; if !backing.is_empty() { match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { - Ok(Some(DB_VERSION)) => { with_journal = true; }, - Ok(Some(DB_VERSION_NO_JOURNAL)) => { with_journal = false; }, + Ok(Some(DB_VERSION)) => {}, v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) } } else { - backing.put(&VERSION_KEY, &encode(&(if prefer_journal { DB_VERSION } else { DB_VERSION_NO_JOURNAL }))).expect("Error writing version to database"); - with_journal = prefer_journal; + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } - - let counters = if with_journal { - Some(Arc::new(RwLock::new(OptionOneDB::read_counters(&backing)))) - } else { - None - }; + + let counters = Some(Arc::new(RwLock::new(OptionOneDB::read_counters(&backing)))); OptionOneDB { overlay: MemoryDB::new(), backing: Arc::new(backing), @@ -108,34 +78,6 @@ impl OptionOneDB { Self::new(dir.to_str().unwrap()) } - /// Drain the overlay and place it into a batch for the DB. - fn batch_overlay_insertions(overlay: &mut MemoryDB, batch: &DBTransaction) -> usize { - let mut inserts = 0usize; - let mut deletes = 0usize; - for i in overlay.drain().into_iter() { - let (key, (value, rc)) = i; - if rc > 0 { - assert!(rc == 1); - batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); - inserts += 1; - } - if rc < 0 { - assert!(rc == -1); - deletes += 1; - } - } - trace!("commit: Inserted {}, Deleted {} nodes", inserts, deletes); - inserts + deletes - } - - /// Just commit the overlay into the backing DB. - fn commit_without_counters(&mut self) -> Result { - let batch = DBTransaction::new(); - let ret = Self::batch_overlay_insertions(&mut self.overlay, &batch); - try!(self.backing.write(batch)); - Ok(ret as u32) - } - fn morph_key(key: &H256, index: u8) -> Bytes { let mut ret = key.bytes().to_owned(); ret.push(index); @@ -217,9 +159,106 @@ impl OptionOneDB { } } - /// Commit all recent insert operations and historical removals from the old era - /// to the backing database. - fn commit_with_counters(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + fn payload(&self, key: &H256) -> Option { + self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) + } + + fn read_counters(db: &Database) -> HashMap { + let mut counters = HashMap::new(); + if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { + let mut era = decode::(&val); + loop { + let mut index = 0usize; + while let Some(rlp_data) = db.get({ + let mut r = RlpStream::new_list(3); + r.append(&era); + r.append(&index); + r.append(&&PADDING[..]); + &r.drain() + }).expect("Low-level database error.") { + trace!("read_counters: era={}, index={}", era, index); + let rlp = Rlp::new(&rlp_data); + let inserts: Vec = rlp.val_at(1); + Self::replay_keys(&inserts, db, &mut counters); + index += 1; + }; + if index == 0 || era == 0 { + break; + } + era -= 1; + } + } + trace!("Recovered {} counters", counters.len()); + counters + } +} + +impl HashDB for OptionOneDB { + fn keys(&self) -> HashMap { + let mut ret: HashMap = HashMap::new(); + for (key, _) in self.backing.iter() { + let h = H256::from_slice(key.deref()); + ret.insert(h, 1); + } + + for (key, refs) in self.overlay.keys().into_iter() { + let refs = *ret.get(&key).unwrap_or(&0) + refs; + ret.insert(key, refs); + } + ret + } + + fn lookup(&self, key: &H256) -> Option<&[u8]> { + let k = self.overlay.raw(key); + match k { + Some(&(ref d, rc)) if rc > 0 => Some(d), + _ => { + if let Some(x) = self.payload(key) { + Some(&self.overlay.denote(key, x).0) + } + else { + None + } + } + } + } + + fn exists(&self, key: &H256) -> bool { + self.lookup(key).is_some() + } + + fn insert(&mut self, value: &[u8]) -> H256 { + self.overlay.insert(value) + } + fn emplace(&mut self, key: H256, value: Bytes) { + self.overlay.emplace(key, value); + } + fn kill(&mut self, key: &H256) { + self.overlay.kill(key); + } +} + +impl JournalDB for OptionOneDB { + fn spawn(&self) -> Box { + Box::new(OptionOneDB { + overlay: MemoryDB::new(), + backing: self.backing.clone(), + counters: self.counters.clone(), + }) + } + + fn mem_used(&self) -> usize { + self.overlay.mem_used() + match self.counters { + Some(ref c) => c.read().unwrap().heap_size_of_children(), + None => 0 + } + } + + fn is_empty(&self) -> bool { + self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + } + + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] @@ -337,114 +376,6 @@ impl OptionOneDB { // trace!("OptionOneDB::commit() deleted {} nodes", deletes); Ok(0) } - - fn payload(&self, key: &H256) -> Option { - self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) - } - - fn read_counters(db: &Database) -> HashMap { - let mut counters = HashMap::new(); - if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); - loop { - let mut index = 0usize; - while let Some(rlp_data) = db.get({ - let mut r = RlpStream::new_list(3); - r.append(&era); - r.append(&index); - r.append(&&PADDING[..]); - &r.drain() - }).expect("Low-level database error.") { - trace!("read_counters: era={}, index={}", era, index); - let rlp = Rlp::new(&rlp_data); - let inserts: Vec = rlp.val_at(1); - Self::replay_keys(&inserts, db, &mut counters); - index += 1; - }; - if index == 0 || era == 0 { - break; - } - era -= 1; - } - } - trace!("Recovered {} counters", counters.len()); - counters - } -} - -impl HashDB for OptionOneDB { - fn keys(&self) -> HashMap { - let mut ret: HashMap = HashMap::new(); - for (key, _) in self.backing.iter() { - let h = H256::from_slice(key.deref()); - ret.insert(h, 1); - } - - for (key, refs) in self.overlay.keys().into_iter() { - let refs = *ret.get(&key).unwrap_or(&0) + refs; - ret.insert(key, refs); - } - ret - } - - fn lookup(&self, key: &H256) -> Option<&[u8]> { - let k = self.overlay.raw(key); - match k { - Some(&(ref d, rc)) if rc > 0 => Some(d), - _ => { - if let Some(x) = self.payload(key) { - Some(&self.overlay.denote(key, x).0) - } - else { - None - } - } - } - } - - fn exists(&self, key: &H256) -> bool { - self.lookup(key).is_some() - } - - fn insert(&mut self, value: &[u8]) -> H256 { - self.overlay.insert(value) - } - fn emplace(&mut self, key: H256, value: Bytes) { - self.overlay.emplace(key, value); - } - fn kill(&mut self, key: &H256) { - self.overlay.kill(key); - } -} - -impl JournalDB for OptionOneDB { - fn spawn(&self) -> Box { - Box::new(OptionOneDB { - overlay: MemoryDB::new(), - backing: self.backing.clone(), - counters: self.counters.clone(), - }) - } - - fn mem_used(&self) -> usize { - self.overlay.mem_used() + match self.counters { - Some(ref c) => c.read().unwrap().heap_size_of_children(), - None => 0 - } - } - - fn is_empty(&self) -> bool { - self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() - } - - fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - let have_counters = self.counters.is_some(); - if have_counters { - self.commit_with_counters(now, id, end) - } else { - self.commit_without_counters() - } - } } #[cfg(test)] diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs new file mode 100644 index 000000000..25e132339 --- /dev/null +++ b/util/src/journaldb/traits.rs @@ -0,0 +1,37 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Disk-backed HashDB implementation. + +use common::*; +use hashdb::*; + +/// A HashDB which can manage a short-term journal potentially containing many forks of mutually +/// exclusive actions. +pub trait JournalDB : HashDB + Send + Sync { + /// Return a copy of ourself, in a box. + fn spawn(&self) -> Box; + + /// Returns heap memory size used + fn mem_used(&self) -> usize; + + /// Check if this database has any commits + fn is_empty(&self) -> bool; + + /// Commit all recent insert operations and canonical historical commits' removals from the + /// old era to the backing database, reverting any non-canonical historical commit's inserts. + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result; +} From ecd33a60931be9616245984149a46aba12457f36 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 13:54:52 +0100 Subject: [PATCH 510/753] fixed U256 and transaction request deserialization, added tests for transaction request --- rpc/src/v1/types/bytes.rs | 2 +- rpc/src/v1/types/transaction_request.rs | 64 ++++++++++++++++++++----- util/bigint/src/uint.rs | 8 +--- util/src/hash.rs | 2 +- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 466fbebde..0b14c30e8 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -20,7 +20,7 @@ use serde::de::Visitor; use util::common::FromHex; /// Wrapper structure around vector of bytes. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct Bytes(Vec); impl Bytes { diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index a61b11c25..d40402ab5 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -19,7 +19,7 @@ use util::numbers::{Uint, U256}; use ethcore::transaction::{Action, Transaction}; use v1::types::Bytes; -#[derive(Debug, Default, Deserialize)] +#[derive(Debug, Default, PartialEq, Deserialize)] pub struct TransactionRequest { pub from: Address, pub to: Option
, @@ -27,28 +27,26 @@ pub struct TransactionRequest { pub gas_price: Option, pub gas: Option, pub value: Option, - pub data: Bytes, + pub data: Option, pub nonce: Option, } impl Into for TransactionRequest { fn into(self) -> Transaction { Transaction { - nonce: self.nonce.unwrap_or(U256::zero()), - action: match self.to { - None => Action::Create, - Some(addr) => Action::Call(addr) - }, - gas: self.gas.unwrap_or(U256::zero()), - gas_price: self.gas_price.unwrap_or(U256::zero()), - value: self.value.unwrap_or(U256::zero()), - data: self.data.to_vec() + nonce: self.nonce.unwrap_or_else(U256::zero), + action: self.to.map_or(Action::Create, Action::Call), + gas: self.gas.unwrap_or_else(U256::zero), + gas_price: self.gas_price.unwrap_or_else(U256::zero), + value: self.value.unwrap_or_else(U256::zero), + data: self.data.map_or_else(Vec::new, |d| d.to_vec()), } } } #[cfg(test)] mod tests { + use serde_json; use util::numbers::{Uint, U256}; use util::hash::Address; use ethcore::transaction::{Transaction, Action}; @@ -63,7 +61,7 @@ mod tests { gas_price: Some(U256::from(20)), gas: Some(U256::from(10_000)), value: Some(U256::from(1)), - data: Bytes::new(vec![10, 20]), + data: Some(Bytes::new(vec![10, 20])), nonce: Some(U256::from(12)), }; @@ -85,7 +83,7 @@ mod tests { gas_price: None, gas: None, value: None, - data: Bytes::new(vec![]), + data: None, nonce: None, }; @@ -98,4 +96,44 @@ mod tests { data: vec![], }, tr.into()); } + + #[test] + fn transaction_request_deserialize() { + let s = r#"{ + "from":"0x0000000000000000000000000000000000000001", + "to":"0x0000000000000000000000000000000000000002", + "gasPrice":"0x1", + "gas":"0x2", + "value":"0x3", + "data":"0x123456", + "nonce":"0x4" + }"#; + let deserialized: TransactionRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, TransactionRequest { + from: Address::from(1), + to: Some(Address::from(2)), + gas_price: Some(U256::from(1)), + gas: Some(U256::from(2)), + value: Some(U256::from(3)), + data: Some(Bytes::new(vec![0x12, 0x34, 0x56])), + nonce: Some(U256::from(4)), + }); + } + + #[test] + fn transaction_request_deserialize_empty() { + let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#; + let deserialized: TransactionRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, TransactionRequest { + from: Address::from(1), + to: None, + gas_price: None, + gas: None, + value: None, + data: None, + nonce: None, + }); + } } diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 959df0944..47888fd88 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -39,7 +39,6 @@ use std::fmt; use std::cmp; -use std::mem; use std::str::{FromStr}; use std::convert::From; use std::hash::{Hash, Hasher}; @@ -788,14 +787,11 @@ macro_rules! construct_uint { fn visit_str(&mut self, value: &str) -> Result where E: serde::Error { // 0x + len - if value.len() != 2 + $n_words / 8 { + if value.len() > 2 + $n_words * 16 { return Err(serde::Error::custom("Invalid length.")); } - match $name::from_str(&value[2..]) { - Ok(val) => Ok(val), - Err(_) => { return Err(serde::Error::custom("Invalid length.")); } - } + $name::from_str(&value[2..]).map_err(|_| serde::Error::custom("Invalid hex value.")) } fn visit_string(&mut self, value: String) -> Result where E: serde::Error { diff --git a/util/src/hash.rs b/util/src/hash.rs index 4eb96b53e..3dc15116d 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -257,7 +257,7 @@ macro_rules! impl_hash { return Err(serde::Error::custom("Invalid length.")); } - value[2..].from_hex().map(|ref v| $from::from_slice(v)).map_err(|_| serde::Error::custom("Invalid valid hex.")) + value[2..].from_hex().map(|ref v| $from::from_slice(v)).map_err(|_| serde::Error::custom("Invalid hex value.")) } fn visit_string(&mut self, value: String) -> Result where E: serde::Error { From 51cfd4b0ea03a7a22ae0c0034a4ac0c8093a05c6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 13:58:11 +0100 Subject: [PATCH 511/753] Remove unneeded clone. --- util/src/overlaydb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index f14677d05..7c9b6b04b 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -36,7 +36,7 @@ use kvdb::{Database}; /// /// `lookup()` and `contains()` maintain normal behaviour - all `insert()` and `remove()` /// queries have an immediate effect in terms of these functions. -#[derive(Clone)] +//#[derive(Clone)] pub struct OverlayDB { overlay: MemoryDB, backing: Arc, From 38d470f3bcc584a3f0f29e3670ebf10e2a2ddad9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 14:45:19 +0100 Subject: [PATCH 512/753] Reorganise command line options into more general engine. --- ethcore/src/client/client.rs | 9 ++---- ethcore/src/client/config.rs | 5 ++-- parity/main.rs | 17 ++++++++---- util/src/journaldb/mod.rs | 53 +++++++++++++++++++++++++++++++++--- util/src/lib.rs | 2 +- 5 files changed, 68 insertions(+), 18 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 70a3eb92a..1148a0140 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -131,7 +131,8 @@ impl Client where V: Verifier { let mut dir = path.to_path_buf(); dir.push(H64::from(spec.genesis_header().hash()).hex()); //TODO: sec/fat: pruned/full versioning - dir.push(format!("v{}-sec-{}", CLIENT_DB_VER_STR, if config.prefer_journal { "pruned" } else { "archive" })); + // version here is a bit useless now, since it's controlled only be the pruning algo. + dir.push(format!("v{}-sec-{}", CLIENT_DB_VER_STR, config.pruning)); let path = dir.as_path(); let gb = spec.genesis_block(); let chain = Arc::new(BlockChain::new(config.blockchain, &gb, path)); @@ -140,11 +141,7 @@ impl Client where V: Verifier { let engine = Arc::new(try!(spec.to_engine())); let state_path_str = state_path.to_str().unwrap(); - let mut state_db = if config.prefer_journal { - new_optiononedb(state_path_str) - } else { - new_archivedb(state_path_str) - }; + let mut state_db = journaldb::new(state_path_str, config.pruning); if state_db.is_empty() && engine.spec().ensure_db_good(state_db.as_hashdb_mut()) { state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 484c8d0c6..89e95ea06 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -16,6 +16,7 @@ pub use block_queue::BlockQueueConfig; pub use blockchain::BlockChainConfig; +use util::journaldb; /// Client configuration. Includes configs for all sub-systems. #[derive(Debug, Default)] @@ -24,8 +25,8 @@ pub struct ClientConfig { pub queue: BlockQueueConfig, /// Blockchain configuration. pub blockchain: BlockChainConfig, - /// Prefer journal rather than archive. - pub prefer_journal: bool, + /// The JournalDB ("pruning") algorithm to use. + pub pruning: journaldb::Algorithm, /// The name of the client instance. pub name: String, } diff --git a/parity/main.rs b/parity/main.rs index b6ed5cba3..bf1e24203 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -80,7 +80,8 @@ Protocol Options: or olympic, frontier, homestead, mainnet, morden, or testnet [default: homestead]. --testnet Equivalent to --chain testnet (geth-compatible). --networkid INDEX Override the network identifier from the chain we are on. - --pruning Client should prune the state/storage trie. + --pruning METHOD Configure pruning of the state/storage trie. METHOD may be one of: archive, + light (experimental) [default: archive]. -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --identity NAME Specify your node's name. @@ -101,7 +102,7 @@ API and Console Options: --jsonrpc-port PORT Specify the port portion of the JSONRPC API server [default: 8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. --jsonrpc-apis APIS Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited - list of API name. Possible name are web3, eth and net. [default: web3,eth,net]. + list of API name. Possible names are web3, eth and net. [default: web3,eth,net]. --rpc Equivalent to --jsonrpc (geth-compatible). --rpcaddr HOST Equivalent to --jsonrpc-addr HOST (geth-compatible). --rpcport PORT Equivalent to --jsonrpc-port PORT (geth-compatible). @@ -141,7 +142,7 @@ struct Args { flag_identity: String, flag_cache: Option, flag_keys_path: String, - flag_pruning: bool, + flag_pruning: String, flag_no_bootstrap: bool, flag_listen_address: String, flag_public_address: Option, @@ -403,7 +404,13 @@ impl Configuration { client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; } } - client_config.prefer_journal = self.args.flag_pruning; + client_config.pruning = match self.args.flag_pruning.as_str() { + "archive" => journaldb::Algorithm::Archive, + "pruned" => journaldb::Algorithm::EarlyMerge, +// "fast" => journaldb::Algorithm::OverlayRecent, // TODO: @arkpar uncomment this once option 2 is merged. +// "slow" => journaldb::Algorithm::RefCounted, // TODO: @gavofyork uncomment this once ref-count algo is merged. + _ => { die!("{}: Invalid pruning method given.", self.args.flag_pruning); } + }; client_config.name = self.args.flag_identity.clone(); client_config.queue.max_mem_use = self.args.flag_queue_max_size; let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); @@ -424,7 +431,7 @@ impl Configuration { self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_addr), self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) ); - SocketAddr::from_str(&url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen host/port given.", url)); + SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); diff --git a/util/src/journaldb/mod.rs b/util/src/journaldb/mod.rs index fdb825d51..0cee7dd8d 100644 --- a/util/src/journaldb/mod.rs +++ b/util/src/journaldb/mod.rs @@ -26,8 +26,53 @@ mod optiononedb; /// Export the JournalDB trait. pub use self::traits::JournalDB; -/// Create a new JournalDB trait object which is an ArchiveDB. -pub fn new_archivedb(path: &str) -> Box { Box::new(archivedb::ArchiveDB::new(path)) } +/// A journal database algorithm. +#[derive(Debug)] +pub enum Algorithm { + /// Keep all keys forever. + Archive, -/// Create a new JournalDB trait object which is an OptionOneDB. -pub fn new_optiononedb(path: &str) -> Box { Box::new(optiononedb::OptionOneDB::new(path)) } + /// Ancient and recent history maintained separately; recent history lasts for particular + /// number of blocks. + /// + /// Inserts go into backing database, journal retains knowledge of whether backing DB key is + /// ancient or recent. Non-canon inserts get explicitly reverted and removed from backing DB. + EarlyMerge, + + /// Ancient and recent history maintained separately; recent history lasts for particular + /// number of blocks. + /// + /// Inserts go into memory overlay, which is tried for key fetches. Memory overlay gets + /// flushed in backing only at end of recent history. + OverlayRecent, + + /// Ancient and recent history maintained separately; recent history lasts for particular + /// number of blocks. + /// + /// References are counted in disk-backed DB. + RefCounted, +} + +impl Default for Algorithm { + fn default() -> Algorithm { Algorithm::Archive } +} + +impl fmt::Display for Algorithm { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", match self { + &Algorithm::Archive => "archive", + &Algorithm::EarlyMerge => "earlymerge", + &Algorithm::OverlayRecent => "overlayrecent", + &Algorithm::RefCounted => "refcounted", + }) + } +} + +/// Create a new JournalDB trait object. +pub fn new(path: &str, algorithm: Algorithm) -> Box { + match algorithm { + Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)), + Algorithm::EarlyMerge => Box::new(optiononedb::OptionOneDB::new(path)), + _ => unimplemented!(), + } +} diff --git a/util/src/lib.rs b/util/src/lib.rs index 59d66a325..de9934f36 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -154,7 +154,7 @@ pub use rlp::*; pub use hashdb::*; pub use memorydb::*; pub use overlaydb::*; -pub use journaldb::*; +pub use journaldb::JournalDB; pub use math::*; pub use crypto::*; pub use triehash::*; From 8ae103087ddc87b3f61f1c0b21dcbb5ce5919fd5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 15:07:43 +0100 Subject: [PATCH 513/753] Fixups for new API. --- ethcore/src/tests/helpers.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 56ea6b1d3..dc3068560 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -252,7 +252,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { pub fn get_temp_journal_db() -> GuardedTempResult> { let temp = RandomTempPath::new(); - let journal_db: Box = Box::new(OptionOneDB::new(temp.as_str())); + let journal_db = journaldb::new(temp.as_str(), journaldb::Algorithm::EarlyMerge); GuardedTempResult { _temp: temp, result: Some(journal_db) @@ -269,7 +269,7 @@ pub fn get_temp_state() -> GuardedTempResult { } pub fn get_temp_journal_db_in(path: &Path) -> Box { - Box::new(OptionOneDB::new(path.to_str().unwrap())) + journaldb::new(path.to_str().unwrap(), journaldb::Algorithm::EarlyMerge) } pub fn get_temp_state_in(path: &Path) -> State { From 197ea7f7d6bc89337215ad72702ac34734f0f71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 14:48:30 +0100 Subject: [PATCH 514/753] Using miner in rpc instead of sync --- miner/src/lib.rs | 43 +++++++++++++++++++++++++++++++++++- miner/src/miner.rs | 49 ++++++++--------------------------------- parity/main.rs | 1 + rpc/src/lib.rs | 2 ++ rpc/src/v1/impls/eth.rs | 18 ++++++++++----- 5 files changed, 67 insertions(+), 46 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 20b5dd7d3..135a15df5 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -63,5 +63,46 @@ mod miner; mod transaction_queue; pub use transaction_queue::TransactionQueue; -pub use miner::{Miner, MinerService}; +pub use miner::{Miner}; +use std::sync::Mutex; +use util::{H256, U256, Address, Bytes}; +use ethcore::client::{BlockChainClient}; +use ethcore::block::{ClosedBlock}; +use ethcore::error::{Error}; +use ethcore::transaction::SignedTransaction; + +/// Miner client API +pub trait MinerService : Send + Sync { + + /// Returns miner's status. + fn status(&self) -> MinerStatus; + + /// Imports transactions to transaction queue. + fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> + where T: Fn(&Address) -> U256; + + /// Removes all transactions from the queue and restart mining operation. + fn clear_and_reset(&self, chain: &BlockChainClient); + + /// called when blocks are imported to chain, updates transactions queue. + fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], retracted: &[H256]); + + /// New chain head event. Restart mining operation. + fn prepare_sealing(&self, chain: &BlockChainClient); + + /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. + fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex>; + + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; +} + +/// Mining status +pub struct MinerStatus { + /// Number of transactions in queue with state `pending` (ready to be included in block) + pub transaction_queue_pending: usize, + /// Number of transactions in queue with state `future` (not yet ready to be included in block) + pub transaction_queue_future: usize, +} diff --git a/miner/src/miner.rs b/miner/src/miner.rs index d2e839101..623af33a0 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -14,50 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::*; -use std::sync::atomic::AtomicBool; use rayon::prelude::*; +use std::sync::{Mutex, RwLock, Arc}; +use std::sync::atomic; +use std::sync::atomic::AtomicBool; + +use util::{H256, U256, Address, Bytes}; use ethcore::views::{BlockView}; use ethcore::client::{BlockChainClient, BlockId}; -use ethcore::block::*; -use ethcore::error::*; +use ethcore::block::{ClosedBlock}; +use ethcore::error::{Error}; use ethcore::transaction::SignedTransaction; -use transaction_queue::{TransactionQueue}; -/// Miner client API -pub trait MinerService : Send + Sync { - - /// Returns miner's status. - fn status(&self) -> MinerStatus; - - /// Imports transactions to transaction queue. - fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> - where T: Fn(&Address) -> U256; - - /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, chain: &BlockChainClient); - - /// called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]); - - /// New chain head event. Restart mining operation. - fn prepare_sealing(&self, chain: &BlockChainClient); - - /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex>; - - /// Submit `seal` as a valid solution for the header of `pow_hash`. - /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; -} - -/// Mining status -pub struct MinerStatus { - /// Number of transactions in queue with state `pending` (ready to be included in block) - pub transaction_queue_pending: usize, - /// Number of transactions in queue with state `future` (not yet ready to be included in block) - pub transaction_queue_future: usize, -} +use super::{MinerService, MinerStatus, TransactionQueue}; /// Keeps track of transactions using priority queue and holds currently mined block. pub struct Miner { @@ -76,7 +45,7 @@ impl Default for Miner { transaction_queue: Mutex::new(TransactionQueue::new()), sealing_enabled: AtomicBool::new(false), sealing_block: Mutex::new(None), - author: RwLock::new(Address::new()), + author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), } } diff --git a/parity/main.rs b/parity/main.rs index d26908f8a..f8a45b01e 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -171,6 +171,7 @@ struct Args { flag_nodekey: Option, flag_nodiscover: bool, flag_maxpeers: Option, + flag_gasprice: String, flag_author: String, flag_extra_data: Option, flag_datadir: Option, diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 103bef546..3096a45c9 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] #![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] +#[macro_use] +extern crate log; extern crate rustc_serialize; extern crate serde; extern crate serde_json; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 9c0f37bc1..c4d649d5a 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -53,7 +53,7 @@ impl EthClient A: AccountProvider, M: MinerService { /// Creates new EthClient. - pub fn new(client: &Arc, sync: &Arc, miner: &Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc, accounts: &Arc, miner: &Arc) -> Self { EthClient { client: Arc::downgrade(client), sync: Arc::downgrade(sync), @@ -189,7 +189,7 @@ impl Eth for EthClient fn block_transaction_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { - BlockNumber::Pending => to_value(&take_weak!(self.sync).status().transaction_queue_pending), + BlockNumber::Pending => to_value(&take_weak!(self.miner).status().transaction_queue_pending), _ => match take_weak!(self.client).block(block_number.into()) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), None => Ok(Value::Null) @@ -292,12 +292,20 @@ impl Eth for EthClient let accounts = take_weak!(self.accounts); match accounts.account_secret(&transaction_request.from) { Ok(secret) => { - let sync = take_weak!(self.sync); + let miner = take_weak!(self.miner); + let client = take_weak!(self.client); let (transaction, _) = transaction_request.to_eth(); let signed_transaction = transaction.sign(&secret); let hash = signed_transaction.hash(); - sync.insert_transaction(signed_transaction); - to_value(&hash) + + let import = miner.import_transactions(vec![signed_transaction], |a: &Address| client.nonce(a)); + match import { + Ok(_) => to_value(&hash), + Err(e) => { + warn!("Error sending transaction: {:?}", e); + to_value(&U256::zero()) + } + } }, Err(_) => { to_value(&U256::zero()) } } From 36ff65d05078c81208eae39adbd470e2d2ea5029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 14:52:47 +0100 Subject: [PATCH 515/753] Fixing warnings --- parity/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index f8a45b01e..e4ce36144 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -338,7 +338,7 @@ impl Configuration { let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host)); Some(SocketAddr::new(host, self.args.flag_port)) } else { - listen_address.clone() + listen_address }; (listen_address, public_address) } @@ -379,9 +379,9 @@ impl Configuration { fn sync_config(&self, spec: &Spec) -> SyncConfig { let mut sync_config = SyncConfig::default(); - sync_config.network_id = self.args.flag_networkid.as_ref().map(|id| { + sync_config.network_id = self.args.flag_networkid.as_ref().map_or(spec.network_id(), |id| { U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --networkid", id)) - }).unwrap_or(spec.network_id()); + }); sync_config } @@ -425,7 +425,7 @@ impl Configuration { } if self.args.cmd_list { println!("Known addresses:"); - for &(addr, _) in secret_store.accounts().unwrap().iter() { + for &(addr, _) in &secret_store.accounts().unwrap() { println!("{:?}", addr); } } From b458452f0e03acf44eda70b238c804afb2b62e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 14:55:56 +0100 Subject: [PATCH 516/753] TestSyncProvider fixes --- rpc/src/v1/tests/helpers/sync_provider.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index a3711d949..631752dfc 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethcore::transaction::SignedTransaction; use ethsync::{SyncProvider, SyncStatus, SyncState}; pub struct Config { @@ -40,7 +39,6 @@ impl TestSyncProvider { num_peers: config.num_peers, num_active_peers: 0, mem_used: 0, - transaction_queue_pending: 0, }, } } @@ -50,9 +48,5 @@ impl SyncProvider for TestSyncProvider { fn status(&self) -> SyncStatus { self.status.clone() } - - fn insert_transaction(&self, _transaction: SignedTransaction) { - unimplemented!() - } } From 5499f4530c0034451e9642fc6bba2eb67cdb321e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 15:01:15 +0100 Subject: [PATCH 517/753] Fix tests. --- ethcore/src/block.rs | 6 +++--- ethcore/src/ethereum/ethash.rs | 4 ++-- ethcore/src/ethereum/mod.rs | 2 +- ethcore/src/state.rs | 2 +- ethcore/src/tests/helpers.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index f3a4feaf0..4f23cf0a0 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -389,7 +389,7 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let b = b.close(); @@ -404,14 +404,14 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index b0c0e4a9f..a97002a2a 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -298,7 +298,7 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let b = b.close(); @@ -311,7 +311,7 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let mut uncle = Header::new(); diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 0d1dcd8d5..8c2ae6b37 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -61,7 +61,7 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64)); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64)); diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 519debcc1..60149d3eb 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -45,7 +45,7 @@ impl State { let mut root = H256::new(); { // init trie and reset root too null - let _ = SecTrieDBMut::new(db.deref_mut(), &mut root); + let _ = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root); } State { diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 0bb6b5015..56ea6b1d3 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -252,7 +252,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { pub fn get_temp_journal_db() -> GuardedTempResult> { let temp = RandomTempPath::new(); - let journal_db = Box::new(OptionOneDB::new(temp.as_str())); + let journal_db: Box = Box::new(OptionOneDB::new(temp.as_str())); GuardedTempResult { _temp: temp, result: Some(journal_db) From 04af38bb0de889f33145bd36c22e6e67f82c4e25 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 18:54:28 +0400 Subject: [PATCH 518/753] fix test compilation --- util/src/journaldb/archivedb.rs | 1 + util/src/journaldb/optiononedb.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 28cc4130a..e7da1b737 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -166,6 +166,7 @@ mod tests { use common::*; use super::*; use hashdb::*; + use journaldb::traits::JournalDB; #[test] fn insert_same_in_fork() { diff --git a/util/src/journaldb/optiononedb.rs b/util/src/journaldb/optiononedb.rs index 58bb88277..dfa7c8ec1 100644 --- a/util/src/journaldb/optiononedb.rs +++ b/util/src/journaldb/optiononedb.rs @@ -61,7 +61,7 @@ impl OptionOneDB { } else { backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } - + let counters = Some(Arc::new(RwLock::new(OptionOneDB::read_counters(&backing)))); OptionOneDB { overlay: MemoryDB::new(), @@ -383,6 +383,7 @@ mod tests { use common::*; use super::*; use hashdb::*; + use journaldb::traits::JournalDB; #[test] fn insert_same_in_fork() { From 0dbe6684ad42ecd1a681b6430bcb2205a995ea7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 15:58:12 +0100 Subject: [PATCH 519/753] adding std::mem --- util/bigint/src/uint.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 3997d2e66..3dfb9dd45 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -36,6 +36,7 @@ //! The functions here are designed to be fast. //! +use std::mem; use std::fmt; use std::cmp; From 179569f9f810b9b9d6352653eb892afb87b2df2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 16:01:18 +0100 Subject: [PATCH 520/753] Adding std::mem back --- util/bigint/src/uint.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 3997d2e66..c18ed839c 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -36,6 +36,9 @@ //! The functions here are designed to be fast. //! + +#[cfg(all(asm_available, target_arch="x86_64"))] +use std::mem; use std::fmt; use std::cmp; From 89dbc2ac25e8ce6eec482143869a160932e50e82 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 18:08:29 +0300 Subject: [PATCH 521/753] [ci skip] update readme to exclude beta spec (stable is ok) --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 4fd2a53cc..47a27e30e 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,6 @@ Then, download and build Parity: git clone https://github.com/ethcore/parity cd parity -# parity should be built with rust beta -multirust override beta - # build in release mode cargo build --release ``` From c6ba378b6b4c4e3117cac3d758e09732c81c131b Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 16:17:09 +0100 Subject: [PATCH 522/753] rpc web3 tests --- rpc/src/v1/tests/mod.rs | 1 + rpc/src/v1/tests/net.rs | 6 +++--- rpc/src/v1/tests/web3.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 rpc/src/v1/tests/web3.rs diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 5ef74987c..3a38ced15 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -17,4 +17,5 @@ //!TODO: load custom blockchain state and test mod net; +mod web3; mod helpers; diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs index 792e469d8..e24045ca6 100644 --- a/rpc/src/v1/tests/net.rs +++ b/rpc/src/v1/tests/net.rs @@ -36,7 +36,7 @@ fn rpc_net_version() { let request = r#"{"jsonrpc": "2.0", "method": "net_version", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"65","id":1}"#; - assert_eq!(io.handle_request(request), Some(response.to_string())); + assert_eq!(io.handle_request(request), Some(response.to_owned())); } #[test] @@ -49,7 +49,7 @@ fn rpc_net_peer_count() { let request = r#"{"jsonrpc": "2.0", "method": "net_peerCount", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x78","id":1}"#; - assert_eq!(io.handle_request(request), Some(response.to_string())); + assert_eq!(io.handle_request(request), Some(response.to_owned())); } #[test] @@ -62,5 +62,5 @@ fn rpc_net_listening() { let request = r#"{"jsonrpc": "2.0", "method": "net_listening", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; - assert_eq!(io.handle_request(request), Some(response.to_string())); + assert_eq!(io.handle_request(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/tests/web3.rs b/rpc/src/v1/tests/web3.rs new file mode 100644 index 000000000..c717d361a --- /dev/null +++ b/rpc/src/v1/tests/web3.rs @@ -0,0 +1,33 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use jsonrpc_core::IoHandler; +use util::version; +use v1::{Web3, Web3Client}; + +#[test] +fn rpc_web3_version() { + let web3 = Web3Client::new().to_delegate(); + let io = IoHandler::new(); + io.add_delegate(web3); + + let v = version().to_owned().replace("Parity/", "Parity//"); + + let request = r#"{"jsonrpc": "2.0", "method": "web3_clientVersion", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"VER","id":1}"#.to_owned().replace("VER", v.as_ref()); + + assert_eq!(io.handle_request(request), Some(response)); +} From 1e40997ff74b25c03a07fcb38e0c89799410bce1 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 22:15:56 +0400 Subject: [PATCH 523/753] state query for archive jdb --- util/src/journaldb/archivedb.rs | 23 +++++++++++++++++++++++ util/src/journaldb/traits.rs | 5 +++++ 2 files changed, 28 insertions(+) diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index e7da1b737..c8c29e765 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -159,6 +159,10 @@ impl JournalDB for ArchiveDB { try!(self.backing.write(batch)); Ok((inserts + deletes) as u32) } + + fn state(&self, id: &H256) -> Option { + self.backing.get_by_prefix(&id.bytes()[0..12]).and_then(|b| Some(b.to_vec())) + } } #[cfg(test)] @@ -385,4 +389,23 @@ mod tests { assert!(jdb.exists(&foo)); } } + + #[test] + fn returns_state() { + let temp = ::devtools::RandomTempPath::new(); + + let key = { + let mut jdb = ArchiveDB::new(temp.as_str()); + let key = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + key + }; + + { + let jdb = ArchiveDB::new(temp.as_str()); + let state = jdb.state(&key); + assert!(state.is_some()); + } + + } } diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index 25e132339..017c24330 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -34,4 +34,9 @@ pub trait JournalDB : HashDB + Send + Sync { /// Commit all recent insert operations and canonical historical commits' removals from the /// old era to the backing database, reverting any non-canonical historical commit's inserts. fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result; + + /// State data query + fn state(&self, _id: &H256) -> Option { + None + } } From 90e20cbcad54787eaf239bef016756a884b03f62 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 20:08:01 +0100 Subject: [PATCH 524/753] additional (failing) sstore test --- util/src/keys/store.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index ea97cc80e..cbef7b5f9 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -381,6 +381,7 @@ mod tests { use super::*; use devtools::*; use common::*; + use crypto::KeyPair; #[test] fn can_insert() { @@ -555,4 +556,15 @@ mod tests { let accounts = sstore.accounts().unwrap(); assert_eq!(30, accounts.len()); } + + #[test] + fn validate_generated_addresses() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + let addr = sstore.new_account("test").unwrap(); + let _ok = sstore.unlock_account(&addr, "test").unwrap(); + let secret = sstore.account_secret(&addr).unwrap(); + let kp = KeyPair::from_secret(secret).unwrap(); + assert_eq!(Address::from(kp.public().sha3()), addr); + } } From b1327a045fa39e5e9552797a5f137de383206517 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 22:47:12 +0400 Subject: [PATCH 525/753] fixed new account generation --- util/src/keys/store.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index cbef7b5f9..cd5fa8427 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -214,12 +214,12 @@ impl SecretStore { /// Creates new account pub fn new_account(&mut self, pass: &str) -> Result { - let secret = H256::random(); + let key_pair = crypto::KeyPair::create().expect("Error creating key-pair. Something wrong with crypto libraries?"); + let address = Address::from(key_pair.public().sha3()); let key_id = H128::random(); - self.insert(key_id.clone(), secret, pass); + self.insert(key_id.clone(), key_pair.secret().clone(), pass); let mut key_file = self.directory.get(&key_id).expect("the key was just inserted"); - let address = Address::random(); key_file.account = Some(address); try!(self.directory.save(key_file)); Ok(address) From e970dd4530cfc20b0af1e86b49a83bcff62f3ec6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 23:09:14 +0400 Subject: [PATCH 526/753] client state data func --- ethcore/src/client/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 1148a0140..8abf3a526 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -466,8 +466,8 @@ impl BlockChainClient for Client where V: Verifier { } } - fn state_data(&self, _hash: &H256) -> Option { - None + fn state_data(&self, hash: &H256) -> Option { + self.state_db.lock().unwrap().state(hash) } fn block_receipts(&self, _hash: &H256) -> Option { From da6f6d57cdc4753c8253866a1fedb84a9ee2f232 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 23:24:44 +0400 Subject: [PATCH 527/753] state data query to client --- ethcore/src/tests/client.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 001d1729b..4818ef69e 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -35,6 +35,19 @@ fn imports_from_empty() { client.flush_queue(); } +#[test] +fn returns_state_root_basic() { + let client_result = generate_dummy_client(6); + let client = client_result.reference(); + + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + let state_root = test_engine.spec().genesis_header().state_root; + + assert!(client.state_data(&state_root).is_some()); + +} + #[test] fn imports_good_block() { let dir = RandomTempPath::new(); From 349584772b6b6bc2c4078ef0fc67d88f023248a6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 23:34:18 +0400 Subject: [PATCH 528/753] redundant lines --- ethcore/src/tests/client.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 4818ef69e..43b426560 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -39,13 +39,11 @@ fn imports_from_empty() { fn returns_state_root_basic() { let client_result = generate_dummy_client(6); let client = client_result.reference(); - let test_spec = get_test_spec(); let test_engine = test_spec.to_engine().unwrap(); let state_root = test_engine.spec().genesis_header().state_root; assert!(client.state_data(&state_root).is_some()); - } #[test] From 19f23f8445bb34daf8ea3eebd9fa6fb733d8329a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 23:37:47 +0400 Subject: [PATCH 529/753] increasing history to be useful for geth fast sync --- ethcore/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8abf3a526..77cf105ed 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -115,7 +115,7 @@ pub struct Client where V: Verifier { verifier: PhantomData, } -const HISTORY: u64 = 1000; +const HISTORY: u64 = 1200; const CLIENT_DB_VER_STR: &'static str = "5.1"; impl Client { From fb51ac0d95504d94b46908ccb7bdc1cf7c59670f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 11 Mar 2016 23:33:01 +0100 Subject: [PATCH 530/753] blockchain receipts rlp generation --- ethcore/src/client/client.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 77cf105ed..4642a0103 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -470,8 +470,12 @@ impl BlockChainClient for Client where V: Verifier { self.state_db.lock().unwrap().state(hash) } - fn block_receipts(&self, _hash: &H256) -> Option { - None + fn block_receipts(&self, hash: &H256) -> Option { + self.chain.block_receipts(hash).and_then(|receipts| { + let mut rlp = RlpStream::new(); + rlp.append(&receipts); + Some(rlp.out()) + }) } fn import_block(&self, bytes: Bytes) -> ImportResult { From 7cfe1d258bebcdf45cad0624b3cd858396464dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 23:49:32 +0100 Subject: [PATCH 531/753] Adding more detailed logging --- util/src/rlp/rlpin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/rlp/rlpin.rs b/util/src/rlp/rlpin.rs index d58fa95e8..9d3fcb2fa 100644 --- a/util/src/rlp/rlpin.rs +++ b/util/src/rlp/rlpin.rs @@ -24,7 +24,7 @@ impl<'a> From> for Rlp<'a> { } /// Data-oriented view onto trusted rlp-slice. -/// +/// /// Unlikely to `UntrustedRlp` doesn't bother you with error /// handling. It assumes that you know what you are doing. #[derive(Debug)] @@ -44,7 +44,7 @@ impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { type Data = &'a [u8]; type Item = Rlp<'a>; type Iter = RlpIterator<'a, 'view>; - + /// Create a new instance of `Rlp` fn new(bytes: &'a [u8]) -> Rlp<'a> { Rlp { @@ -116,7 +116,7 @@ impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { impl <'a, 'view> Rlp<'a> where 'a: 'view { fn view_as_val(r: &R) -> T where R: View<'a, 'view>, T: RlpDecodable { let res: Result = r.as_val(); - res.unwrap_or_else(|_| panic!()) + res.unwrap_or_else(|e| panic!("DecodeError: {}", e)) } /// Decode into an object From 12e1abdfb70e3cd2a662cbcbb4b44bbbe3c56f41 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 09:51:17 +0100 Subject: [PATCH 532/753] Port fixes to new infrastrtcutre. --- util/src/journaldb/optiononedb.rs | 572 +++++++++++++++++++++++++----- 1 file changed, 492 insertions(+), 80 deletions(-) diff --git a/util/src/journaldb/optiononedb.rs b/util/src/journaldb/optiononedb.rs index dfa7c8ec1..b51d0819d 100644 --- a/util/src/journaldb/optiononedb.rs +++ b/util/src/journaldb/optiononedb.rs @@ -25,6 +25,34 @@ use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; +#[derive(Clone, PartialEq, Eq)] +struct RefInfo { + queue_refs: usize, + in_archive: bool, +} + +impl HeapSizeOf for RefInfo { + fn heap_size_of_children(&self) -> usize { 0 } +} + +impl fmt::Display for RefInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}+{}", self.queue_refs, if self.in_archive {1} else {0}) + } +} + +impl fmt::Debug for RefInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}+{}", self.queue_refs, if self.in_archive {1} else {0}) + } +} + +#[derive(Clone, PartialEq, Eq)] +enum RemoveFrom { + Queue, + Archive, +} + /// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// @@ -35,7 +63,7 @@ use std::env; pub struct OptionOneDB { overlay: MemoryDB, backing: Arc, - counters: Option>>>, + refs: Option>>>, } // all keys must be at least 12 bytes @@ -62,11 +90,11 @@ impl OptionOneDB { backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } - let counters = Some(Arc::new(RwLock::new(OptionOneDB::read_counters(&backing)))); + let refs = Some(Arc::new(RwLock::new(OptionOneDB::read_refs(&backing)))); OptionOneDB { overlay: MemoryDB::new(), backing: Arc::new(backing), - counters: counters, + refs: refs, } } @@ -91,11 +119,14 @@ impl OptionOneDB { backing.get(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?").is_some() } - fn insert_keys(inserts: &[(H256, Bytes)], backing: &Database, counters: &mut HashMap, batch: &DBTransaction) { + fn insert_keys(inserts: &[(H256, Bytes)], backing: &Database, refs: &mut HashMap, batch: &DBTransaction, trace: bool) { for &(ref h, ref d) in inserts { - if let Some(c) = counters.get_mut(h) { + if let Some(c) = refs.get_mut(h) { // already counting. increment. - *c += 1; + c.queue_refs += 1; + if trace { + trace!(target: "jdb.fine", " insert({}): In queue: Incrementing refs to {}", h, c.queue_refs); + } continue; } @@ -103,7 +134,10 @@ impl OptionOneDB { if backing.get(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?").is_some() { // already in the backing DB. start counting, and remember it was already in. Self::set_already_in(batch, &h); - counters.insert(h.clone(), 1); + refs.insert(h.clone(), RefInfo{queue_refs: 1, in_archive: true}); + if trace { + trace!(target: "jdb.fine", " insert({}): New to queue, in DB: Recording and inserting into queue", h); + } continue; } @@ -111,60 +145,104 @@ impl OptionOneDB { //Self::reset_already_in(&h); assert!(!Self::is_already_in(backing, &h)); batch.put(&h.bytes(), d).expect("Low-level database error. Some issue with your hard disk?"); + refs.insert(h.clone(), RefInfo{queue_refs: 1, in_archive: false}); + if trace { + trace!(target: "jdb.fine", " insert({}): New to queue, not in DB: Inserting into queue and DB", h); + } } } - fn replay_keys(inserts: &[H256], backing: &Database, counters: &mut HashMap) { - trace!("replay_keys: inserts={:?}, counters={:?}", inserts, counters); + fn replay_keys(inserts: &[H256], backing: &Database, refs: &mut HashMap) { + trace!(target: "jdb.fine", "replay_keys: inserts={:?}, refs={:?}", inserts, refs); for h in inserts { - if let Some(c) = counters.get_mut(h) { + if let Some(c) = refs.get_mut(h) { // already counting. increment. - *c += 1; + c.queue_refs += 1; continue; } // this is the first entry for this node in the journal. // it is initialised to 1 if it was already in. - if Self::is_already_in(backing, h) { - trace!("replace_keys: Key {} was already in!", h); - counters.insert(h.clone(), 1); - } + refs.insert(h.clone(), RefInfo{queue_refs: 1, in_archive: Self::is_already_in(backing, h)}); } - trace!("replay_keys: (end) counters={:?}", counters); + trace!(target: "jdb.fine", "replay_keys: (end) refs={:?}", refs); } - fn kill_keys(deletes: Vec, counters: &mut HashMap, batch: &DBTransaction) { - for h in deletes.into_iter() { - let mut n: Option = None; - if let Some(c) = counters.get_mut(&h) { - if *c > 1 { - *c -= 1; + fn kill_keys(deletes: &Vec, refs: &mut HashMap, batch: &DBTransaction, from: RemoveFrom, trace: bool) { + // with a kill on {queue_refs: 1, in_archive: true}, we have two options: + // - convert to {queue_refs: 1, in_archive: false} (i.e. remove it from the conceptual archive) + // - convert to {queue_refs: 0, in_archive: true} (i.e. remove it from the conceptual queue) + // (the latter option would then mean removing the RefInfo, since it would no longer be counted in the queue.) + // both are valid, but we switch between them depending on context. + // All inserts in queue (i.e. those which may yet be reverted) have an entry in refs. + for h in deletes.iter() { + let mut n: Option = None; + if let Some(c) = refs.get_mut(h) { + if c.in_archive && from == RemoveFrom::Archive { + c.in_archive = false; + Self::reset_already_in(batch, h); + if trace { + trace!(target: "jdb.fine", " kill({}): In archive, 1 in queue: Reducing to queue only and recording", h); + } + continue; + } else if c.queue_refs > 1 { + c.queue_refs -= 1; + if trace { + trace!(target: "jdb.fine", " kill({}): In queue > 1 refs: Decrementing ref count to {}", h, c.queue_refs); + } continue; } else { - n = Some(*c); + n = Some(c.clone()); } } match n { - Some(i) if i == 1 => { - counters.remove(&h); - Self::reset_already_in(batch, &h); + Some(RefInfo{queue_refs: 1, in_archive: true}) => { + refs.remove(h); + Self::reset_already_in(batch, h); + if trace { + trace!(target: "jdb.fine", " kill({}): In archive, 1 in queue: Removing from queue and leaving in archive", h); + } + } + Some(RefInfo{queue_refs: 1, in_archive: false}) => { + refs.remove(h); + batch.delete(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + if trace { + trace!(target: "jdb.fine", " kill({}): Not in archive, only 1 ref in queue: Removing from queue and DB", h); + } } None => { // Gets removed when moving from 1 to 0 additional refs. Should never be here at 0 additional refs. //assert!(!Self::is_already_in(db, &h)); batch.delete(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + if trace { + trace!(target: "jdb.fine", " kill({}): Not in queue - MUST BE IN ARCHIVE: Removing from DB", h); + } } - _ => panic!("Invalid value in counters: {:?}", n), + _ => panic!("Invalid value in refs: {:?}", n), } } } + #[cfg(test)] + fn can_reconstruct_refs(&self) -> bool { + let reconstructed = Self::read_refs(&self.backing); + let refs = self.refs.as_ref().unwrap().write().unwrap(); + if *refs != reconstructed { + let clean_refs = refs.iter().filter_map(|(k, v)| if reconstructed.get(k) == Some(v) {None} else {Some((k.clone(), v.clone()))}).collect::>(); + let clean_recon = reconstructed.into_iter().filter_map(|(k, v)| if refs.get(&k) == Some(&v) {None} else {Some((k.clone(), v.clone()))}).collect::>(); + warn!(target: "jdb", "mem: {:?} != log: {:?}", clean_refs, clean_recon); + false + } else { + true + } + } + fn payload(&self, key: &H256) -> Option { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } - fn read_counters(db: &Database) -> HashMap { - let mut counters = HashMap::new(); + fn read_refs(db: &Database) -> HashMap { + let mut refs = HashMap::new(); if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { let mut era = decode::(&val); loop { @@ -176,10 +254,9 @@ impl OptionOneDB { r.append(&&PADDING[..]); &r.drain() }).expect("Low-level database error.") { - trace!("read_counters: era={}, index={}", era, index); let rlp = Rlp::new(&rlp_data); let inserts: Vec = rlp.val_at(1); - Self::replay_keys(&inserts, db, &mut counters); + Self::replay_keys(&inserts, db, &mut refs); index += 1; }; if index == 0 || era == 0 { @@ -188,10 +265,9 @@ impl OptionOneDB { era -= 1; } } - trace!("Recovered {} counters", counters.len()); - counters + refs } -} + } impl HashDB for OptionOneDB { fn keys(&self) -> HashMap { @@ -243,23 +319,23 @@ impl JournalDB for OptionOneDB { Box::new(OptionOneDB { overlay: MemoryDB::new(), backing: self.backing.clone(), - counters: self.counters.clone(), + refs: self.refs.clone(), }) } - fn mem_used(&self) -> usize { - self.overlay.mem_used() + match self.counters { - Some(ref c) => c.read().unwrap().heap_size_of_children(), - None => 0 - } - } - fn is_empty(&self) -> bool { self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() } + fn mem_used(&self) -> usize { + self.overlay.mem_used() + match self.refs { + Some(ref c) => c.read().unwrap().heap_size_of_children(), + None => 0 + } + } + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: + // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, n] => [ ... ] @@ -304,9 +380,9 @@ impl JournalDB for OptionOneDB { // // record new commit's details. - trace!("commit: #{} ({}), end era: {:?}", now, id, end); - let mut counters = self.counters.as_ref().unwrap().write().unwrap(); + let mut refs = self.refs.as_ref().unwrap().write().unwrap(); let batch = DBTransaction::new(); + let trace = false; { let mut index = 0usize; let mut last; @@ -323,6 +399,11 @@ impl JournalDB for OptionOneDB { } let drained = self.overlay.drain(); + + if trace { + trace!(target: "jdb", "commit: #{} ({}), end era: {:?}", now, id, end); + } + let removes: Vec = drained .iter() .filter_map(|(k, &(_, c))| if c < 0 {Some(k.clone())} else {None}) @@ -332,6 +413,9 @@ impl JournalDB for OptionOneDB { .filter_map(|(k, (v, r))| if r > 0 { assert!(r == 1); Some((k, v)) } else { assert!(r >= -1); None }) .collect(); + + // TODO: check all removes are in the db. + let mut r = RlpStream::new_list(3); r.append(id); @@ -344,7 +428,12 @@ impl JournalDB for OptionOneDB { r.begin_list(inserts.len()); inserts.iter().foreach(|&(k, _)| {r.append(&k);}); r.append(&removes); - Self::insert_keys(&inserts, &self.backing, &mut counters, &batch); + Self::insert_keys(&inserts, &self.backing, &mut refs, &batch, trace); + if trace { + let ins = inserts.iter().map(|&(k, _)| k).collect::>(); + trace!(target: "jdb.ops", " Inserts: {:?}", ins); + trace!(target: "jdb.ops", " Deletes: {:?}", removes); + } try!(batch.put(&last, r.as_raw())); try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); } @@ -363,17 +452,64 @@ impl JournalDB for OptionOneDB { })) { let rlp = Rlp::new(&rlp_data); let inserts: Vec = rlp.val_at(1); - let deletes: Vec = rlp.val_at(2); - // Collect keys to be removed. These are removed keys for canonical block, inserted for non-canonical - Self::kill_keys(if canon_id == rlp.val_at(0) {deletes} else {inserts}, &mut counters, &batch); + + if canon_id == rlp.val_at(0) { + // Collect keys to be removed. Canon block - remove the (enacted) deletes. + let deletes: Vec = rlp.val_at(2); + if trace { + trace!(target: "jdb.ops", " Expunging: {:?}", deletes); + } + Self::kill_keys(&deletes, &mut refs, &batch, RemoveFrom::Archive, trace); + + if trace { + trace!(target: "jdb.ops", " Finalising: {:?}", inserts); + } + for k in inserts.iter() { + match refs.get(k).cloned() { + None => { + // [in archive] -> SHIFT remove -> SHIFT insert None->Some{queue_refs: 1, in_archive: true} -> TAKE remove Some{queue_refs: 1, in_archive: true}->None -> TAKE insert + // already expunged from the queue (which is allowed since the key is in the archive). + // leave well alone. + } + Some( RefInfo{queue_refs: 1, in_archive: false} ) => { + // just delete the refs entry. + refs.remove(k); + } + Some( RefInfo{queue_refs: x, in_archive: false} ) => { + // must set already in; , + Self::set_already_in(&batch, k); + refs.insert(k.clone(), RefInfo{ queue_refs: x - 1, in_archive: true }); + } + Some( RefInfo{queue_refs: _, in_archive: true} ) => { + // Invalid! Reinserted the same key twice. + warn!("Key {} inserted twice into same fork.", k); + } + } + } + } else { + // Collect keys to be removed. Non-canon block - remove the (reverted) inserts. + if trace { + trace!(target: "jdb.ops", " Reverting: {:?}", inserts); + } + Self::kill_keys(&inserts, &mut refs, &batch, RemoveFrom::Queue, trace); + } + try!(batch.delete(&last)); index += 1; } - trace!("OptionOneDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); + if trace { + trace!(target: "jdb", "delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); + } } try!(self.backing.write(batch)); -// trace!("OptionOneDB::commit() deleted {} nodes", deletes); + + // Comment out for now. TODO: automatically enable in tests. + + if trace { + trace!(target: "jdb", "OK: {:?}", refs.clone()); + } + Ok(0) } } @@ -383,26 +519,34 @@ mod tests { use common::*; use super::*; use hashdb::*; - use journaldb::traits::JournalDB; + use log::init_log; #[test] fn insert_same_in_fork() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = JournalDB::new_temp(); let x = jdb.insert(b"X"); jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(3, &b"1002a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(4, &b"1003a".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&x); jdb.commit(3, &b"1002b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); let x = jdb.insert(b"X"); jdb.commit(4, &b"1003b".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(5, &b"1004a".sha3(), Some((3, b"1002a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.commit(6, &b"1005a".sha3(), Some((4, b"1003a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&x)); } @@ -410,29 +554,35 @@ mod tests { #[test] fn long_history() { // history is 3 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = JournalDB::new_temp(); let h = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.remove(&h); jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&h)); jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&h)); } #[test] fn complex() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = JournalDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); @@ -440,6 +590,7 @@ mod tests { jdb.remove(&bar); let baz = jdb.insert(b"baz"); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); assert!(jdb.exists(&baz)); @@ -447,17 +598,20 @@ mod tests { let foo = jdb.insert(b"foo"); jdb.remove(&baz); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&bar)); assert!(jdb.exists(&baz)); jdb.remove(&foo); jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&bar)); assert!(!jdb.exists(&baz)); jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); assert!(!jdb.exists(&bar)); assert!(!jdb.exists(&baz)); @@ -466,26 +620,30 @@ mod tests { #[test] fn fork() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = JournalDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.remove(&foo); let baz = jdb.insert(b"baz"); jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&bar); jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); assert!(jdb.exists(&baz)); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&baz)); assert!(!jdb.exists(&bar)); @@ -494,39 +652,117 @@ mod tests { #[test] fn overwrite() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = JournalDB::new_temp(); let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.insert(b"foo"); assert!(jdb.exists(&foo)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); jdb.commit(3, &b"2".sha3(), Some((0, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); } #[test] - fn fork_same_key() { - // history is 1 - let mut jdb = OptionOneDB::new_temp(); + fn fork_same_key_one() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); let foo = jdb.insert(b"foo"); jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.insert(b"foo"); jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); } + #[test] + fn fork_same_key_other() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_ins_del_ins() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(4, &b"4a".sha3(), Some((2, b"2a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5a".sha3(), Some((3, b"3a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } #[test] fn reopen() { @@ -535,81 +771,257 @@ mod tests { let bar = H256::random(); let foo = { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.emplace(bar.clone(), b"bar".to_vec()); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); foo }; { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); } { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); } } #[test] - fn reopen_remove() { + fn insert_delete_insert_delete_insert_expunge() { + init_log(); let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let foo = { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn forked_insert_delete_insert_delete_insert_expunge() { + init_log(); + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn broken_assert() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); // BROKEN + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + + #[test] + fn reopen_test() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = JournalDB::new(dir.to_str().unwrap()); + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.remove(&bar); + jdb.commit(6, &b"6".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.insert(b"bar"); + jdb.commit(7, &b"7".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn reopen_remove_three() { + init_log(); + + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let foo = b"foo".sha3(); + + { + let mut jdb = JournalDB::new(dir.to_str().unwrap()); // history is 1 - let foo = jdb.insert(b"foo"); + jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); - jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); // foo is ancient history. - jdb.insert(b"foo"); - jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); - foo - }; - - { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.remove(&foo); - jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + jdb.commit(2, &b"2".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); - jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); - jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + jdb.commit(4, &b"4".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + + jdb.commit(5, &b"5".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + + jdb.commit(6, &b"6".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); } } + #[test] fn reopen_fork() { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); let (foo, bar, baz) = { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&foo); let baz = jdb.insert(b"baz"); jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); jdb.remove(&bar); jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); (foo, bar, baz) }; { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = JournalDB::new(dir.to_str().unwrap()); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&baz)); assert!(!jdb.exists(&bar)); From e6a273f3a796f3353985fdf34a32d26838e3c5a9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 09:53:54 +0100 Subject: [PATCH 533/753] Fix tests. --- util/src/journaldb/optiononedb.rs | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/util/src/journaldb/optiononedb.rs b/util/src/journaldb/optiononedb.rs index b51d0819d..567f620b1 100644 --- a/util/src/journaldb/optiononedb.rs +++ b/util/src/journaldb/optiononedb.rs @@ -524,7 +524,7 @@ mod tests { #[test] fn insert_same_in_fork() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let x = jdb.insert(b"X"); jdb.commit(1, &b"1".sha3(), None).unwrap(); @@ -554,7 +554,7 @@ mod tests { #[test] fn long_history() { // history is 3 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let h = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -577,7 +577,7 @@ mod tests { #[test] fn complex() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -620,7 +620,7 @@ mod tests { #[test] fn fork() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -652,7 +652,7 @@ mod tests { #[test] fn overwrite() { // history is 1 - let mut jdb = JournalDB::new_temp(); + let mut jdb = OptionOneDB::new_temp(); let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -677,7 +677,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -705,7 +705,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -733,7 +733,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -771,7 +771,7 @@ mod tests { let bar = H256::random(); let foo = { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.emplace(bar.clone(), b"bar".to_vec()); @@ -781,14 +781,14 @@ mod tests { }; { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); } { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); @@ -803,7 +803,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 4 let foo = jdb.insert(b"foo"); @@ -832,7 +832,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 4 let foo = jdb.insert(b"foo"); @@ -881,7 +881,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); @@ -912,7 +912,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 4 let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -952,7 +952,7 @@ mod tests { let foo = b"foo".sha3(); { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 1 jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -973,7 +973,7 @@ mod tests { assert!(jdb.exists(&foo)); // incantation to reopen the db - }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + }; { let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(4, &b"4".sha3(), Some((2, b"2".sha3()))).unwrap(); @@ -981,14 +981,14 @@ mod tests { assert!(jdb.exists(&foo)); // incantation to reopen the db - }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + }; { let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.commit(5, &b"5".sha3(), Some((3, b"3".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); // incantation to reopen the db - }; { let mut jdb = JournalDB::new(dir.to_str().unwrap()); + }; { let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.commit(6, &b"6".sha3(), Some((4, b"4".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -1001,7 +1001,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); let (foo, bar, baz) = { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -1019,7 +1019,7 @@ mod tests { }; { - let mut jdb = JournalDB::new(dir.to_str().unwrap()); + let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); From 874393ba06dbce3c91ab59afb3b110c37c1b1896 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 09:57:57 +0100 Subject: [PATCH 534/753] Fix tests, --- util/src/journaldb/archivedb.rs | 2 +- util/src/journaldb/optiononedb.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index e7da1b737..a8b9c1f74 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -364,7 +364,7 @@ mod tests { fn reopen_fork() { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let (foo, bar, baz) = { + let (foo, _, _) = { let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); diff --git a/util/src/journaldb/optiononedb.rs b/util/src/journaldb/optiononedb.rs index 567f620b1..e44c337db 100644 --- a/util/src/journaldb/optiononedb.rs +++ b/util/src/journaldb/optiononedb.rs @@ -518,6 +518,7 @@ impl JournalDB for OptionOneDB { mod tests { use common::*; use super::*; + use super::super::traits::JournalDB; use hashdb::*; use log::init_log; From e10457d2352bc8a18c266f79d2ab224d62821836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 12 Mar 2016 09:59:57 +0100 Subject: [PATCH 535/753] Bumping clippy --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- util/Cargo.toml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f26ac923..ce508c937 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "parity" version = "0.9.99" dependencies = [ - "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -94,7 +94,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.49" +version = "0.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -207,7 +207,7 @@ dependencies = [ name = "ethcore" version = "0.9.99" dependencies = [ - "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", @@ -233,7 +233,7 @@ dependencies = [ name = "ethcore-rpc" version = "0.9.99" dependencies = [ - "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", "ethcore 0.9.99", "ethcore-util 0.9.99", @@ -256,7 +256,7 @@ dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", "chrono 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -288,7 +288,7 @@ dependencies = [ name = "ethsync" version = "0.9.99" dependencies = [ - "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", diff --git a/Cargo.toml b/Cargo.toml index 77d1e57ae..efe794d5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } fdlimit = { path = "util/fdlimit" } daemonize = "0.2" number_prefix = "0.2" -clippy = { version = "0.0.49", optional = true } +clippy = { version = "0.0.50", optional = true } ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 5ef83842f..be4212f5d 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -17,7 +17,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.49", optional = true } +clippy = { version = "0.0.50", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index a1f154ca8..900b10548 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,7 +18,7 @@ ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } -clippy = { version = "0.0.49", optional = true } +clippy = { version = "0.0.50", optional = true } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index cf0027368..6022beb9c 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore Date: Sat, 12 Mar 2016 10:07:55 +0100 Subject: [PATCH 536/753] Fixing warnings --- ethcore/src/client/test_client.rs | 8 +++++++- util/src/keys/store.rs | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 207f1090f..9b311081c 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -55,9 +55,15 @@ pub enum EachBlockWith { UncleAndTransaction } +impl Default for TestBlockChainClient { + fn default() -> Self { + TestBlockChainClient::new() + } +} + impl TestBlockChainClient { /// Creates new test client. - pub fn new() -> TestBlockChainClient { + pub fn new() -> Self { let mut client = TestBlockChainClient { blocks: RwLock::new(HashMap::new()), diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 6a5efc87d..37786be8b 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -120,9 +120,15 @@ impl AccountProvider for AccountService { } } +impl Default for AccountService { + fn default() -> Self { + AccountService::new() + } +} + impl AccountService { /// New account service with the default location - pub fn new() -> AccountService { + pub fn new() -> Self { let secret_store = RwLock::new(SecretStore::new()); secret_store.write().unwrap().try_import_existing(); AccountService { From 4b6e1dd4d2e4e62efa92db028cb77bfbdbfb51c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 12 Mar 2016 10:07:55 +0100 Subject: [PATCH 537/753] Fixing warnings --- ethcore/src/block_queue.rs | 2 +- ethcore/src/chainfilter/tests.rs | 8 +++++- ethcore/src/client/test_client.rs | 8 +++++- ethcore/src/externalities.rs | 8 +++++- ethcore/src/verification/verification.rs | 8 +++++- parity/main.rs | 17 +++++++----- util/src/journaldb/archivedb.rs | 2 +- util/src/keys/store.rs | 10 +++++-- util/src/network/connection.rs | 34 ++++++++++++++++++------ 9 files changed, 74 insertions(+), 23 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 50db23dfe..042df1dc1 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -523,7 +523,7 @@ mod tests { let engine = spec.to_engine().unwrap(); let mut config = BlockQueueConfig::default(); config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000 - let mut queue = BlockQueue::new(config, Arc::new(engine), IoChannel::disconnected()); + let queue = BlockQueue::new(config, Arc::new(engine), IoChannel::disconnected()); assert!(!queue.queue_info().is_full()); let mut blocks = get_good_dummy_block_seq(50); for b in blocks.drain(..) { diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs index 08af44720..7dac29f11 100644 --- a/ethcore/src/chainfilter/tests.rs +++ b/ethcore/src/chainfilter/tests.rs @@ -28,9 +28,15 @@ pub struct MemoryCache { blooms: HashMap, } +impl Default for MemoryCache { + fn default() -> Self { + MemoryCache::new() + } +} + impl MemoryCache { /// Default constructor for MemoryCache - pub fn new() -> MemoryCache { + pub fn new() -> Self { MemoryCache { blooms: HashMap::new() } } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 207f1090f..9b311081c 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -55,9 +55,15 @@ pub enum EachBlockWith { UncleAndTransaction } +impl Default for TestBlockChainClient { + fn default() -> Self { + TestBlockChainClient::new() + } +} + impl TestBlockChainClient { /// Creates new test client. - pub fn new() -> TestBlockChainClient { + pub fn new() -> Self { let mut client = TestBlockChainClient { blocks: RwLock::new(HashMap::new()), diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 598921580..d37bc20fb 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -301,8 +301,14 @@ mod tests { env_info: EnvInfo } + impl Default for TestSetup { + fn default() -> Self { + TestSetup::new() + } + } + impl TestSetup { - fn new() -> TestSetup { + fn new() -> Self { TestSetup { state: get_temp_state(), engine: get_test_spec().to_engine().unwrap(), diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index ed3db3791..60cbed56c 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -255,8 +255,14 @@ mod tests { numbers: HashMap, } + impl Default for TestBlockChain { + fn default() -> Self { + TestBlockChain::new() + } + } + impl TestBlockChain { - pub fn new() -> TestBlockChain { + pub fn new() -> Self { TestBlockChain { blocks: HashMap::new(), numbers: HashMap::new(), diff --git a/parity/main.rs b/parity/main.rs index 840921dce..85e29a0ae 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -315,7 +315,7 @@ impl Configuration { fn init_nodes(&self, spec: &Spec) -> Vec { let mut r = if self.args.flag_no_bootstrap { Vec::new() } else { spec.nodes().clone() }; if let Some(ref x) = self.args.flag_bootnodes { - r.extend(x.split(",").map(|s| Self::normalize_enode(s).unwrap_or_else(|| die!("{}: Invalid node address format given for a boot node.", s)))); + r.extend(x.split(',').map(|s| Self::normalize_enode(s).unwrap_or_else(|| die!("{}: Invalid node address format given for a boot node.", s)))); } r } @@ -328,7 +328,7 @@ impl Configuration { let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host)); Some(SocketAddr::new(host, self.args.flag_port)) } else { - listen_address.clone() + listen_address }; (listen_address, public_address) } @@ -389,7 +389,7 @@ impl Configuration { } if self.args.cmd_list { println!("Known addresses:"); - for &(addr, _) in secret_store.accounts().unwrap().iter() { + for &(addr, _) in &secret_store.accounts().unwrap() { println!("{:?}", addr); } } @@ -407,7 +407,11 @@ impl Configuration { let spec = self.spec(); let net_settings = self.net_settings(&spec); let mut sync_config = SyncConfig::default(); - sync_config.network_id = self.args.flag_networkid.as_ref().map(|id| U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --networkid", id))).unwrap_or(spec.network_id()); + sync_config.network_id = self.args.flag_networkid.as_ref().map_or(spec.network_id(), |id| { + U256::from_str(id).unwrap_or_else(|_| { + die!("{}: Invalid index given with --networkid", id) + }) + }); // Build client let mut client_config = ClientConfig::default(); @@ -422,8 +426,7 @@ impl Configuration { } } client_config.pruning = match self.args.flag_pruning.as_str() { - "" => journaldb::Algorithm::Archive, - "archive" => journaldb::Algorithm::Archive, + "" | "archive" => journaldb::Algorithm::Archive, "pruned" => journaldb::Algorithm::EarlyMerge, // "fast" => journaldb::Algorithm::OverlayRecent, // TODO: @arkpar uncomment this once option 2 is merged. // "slow" => journaldb::Algorithm::RefCounted, // TODO: @gavofyork uncomment this once ref-count algo is merged. @@ -453,7 +456,7 @@ impl Configuration { let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - let server_handler = setup_rpc_server(service.client(), sync.clone(), account_service.clone(), &url, cors, apis.split(",").collect()); + let server_handler = setup_rpc_server(service.client(), sync.clone(), account_service.clone(), &url, cors, apis.split(',').collect()); if let Some(handler) = server_handler { panic_handler.forward_from(handler.deref()); } diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index e7da1b737..f92058f92 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -364,7 +364,7 @@ mod tests { fn reopen_fork() { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let (foo, bar, baz) = { + let (foo, _bar, _baz) = { let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 6a5efc87d..d514863bb 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -120,9 +120,15 @@ impl AccountProvider for AccountService { } } +impl Default for AccountService { + fn default() -> Self { + AccountService::new() + } +} + impl AccountService { /// New account service with the default location - pub fn new() -> AccountService { + pub fn new() -> Self { let secret_store = RwLock::new(SecretStore::new()); secret_store.write().unwrap().try_import_existing(); AccountService { @@ -568,7 +574,7 @@ mod tests { let temp = RandomTempPath::create_dir(); let mut sstore = SecretStore::new_test(&temp); let addr = sstore.new_account("test").unwrap(); - let _ok = sstore.unlock_account(&addr, "test").unwrap(); + sstore.unlock_account(&addr, "test").unwrap(); let secret = sstore.account_secret(&addr).unwrap(); let kp = KeyPair::from_secret(secret).unwrap(); assert_eq!(Address::from(kp.public().sha3()), addr); diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index fe65be6d1..a560c1a91 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -160,12 +160,12 @@ impl Connection { } } - /// Get socket token + /// Get socket token pub fn token(&self) -> StreamToken { self.token } - /// Replace socket token + /// Replace socket token pub fn set_token(&mut self, token: StreamToken) { self.token = token; } @@ -261,13 +261,13 @@ pub struct EncryptedConnection { } impl EncryptedConnection { - - /// Get socket token + + /// Get socket token pub fn token(&self) -> StreamToken { self.connection.token } - /// Replace socket token + /// Replace socket token pub fn set_token(&mut self, token: StreamToken) { self.connection.set_token(token); } @@ -513,8 +513,14 @@ mod tests { buf_size: usize, } + impl Default for TestSocket { + fn default() -> Self { + TestSocket::new() + } + } + impl TestSocket { - fn new() -> TestSocket { + fn new() -> Self { TestSocket { read_buffer: vec![], write_buffer: vec![], @@ -593,8 +599,14 @@ mod tests { type TestConnection = GenericConnection; + impl Default for TestConnection { + fn default() -> Self { + TestConnection::new() + } + } + impl TestConnection { - pub fn new() -> TestConnection { + pub fn new() -> Self { TestConnection { token: 999998888usize, socket: TestSocket::new(), @@ -609,8 +621,14 @@ mod tests { type TestBrokenConnection = GenericConnection; + impl Default for TestBrokenConnection { + fn default() -> Self { + TestBrokenConnection::new() + } + } + impl TestBrokenConnection { - pub fn new() -> TestBrokenConnection { + pub fn new() -> Self { TestBrokenConnection { token: 999998888usize, socket: TestBrokenSocket { error: "test broken socket".to_owned() }, From 9424d530627ba0d185bb505a737f4b4121c526b6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 10:37:27 +0100 Subject: [PATCH 538/753] Update lib.rs --- miner/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 10da070a4..9c2ad9ba5 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -88,7 +88,7 @@ pub trait MinerService : Send + Sync { /// Removes all transactions from the queue and restart mining operation. fn clear_and_reset(&self, chain: &BlockChainClient); - /// called when blocks are imported to chain, updates transactions queue. + /// Called when blocks are imported to chain, updates transactions queue. fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], retracted: &[H256]); /// New chain head event. Restart mining operation. From c6dc6c0c41c45ee4279952120fb4112c55cd9932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 12 Mar 2016 10:41:35 +0100 Subject: [PATCH 539/753] One more warning --- util/src/journaldb/overlay.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/util/src/journaldb/overlay.rs b/util/src/journaldb/overlay.rs index e91709041..76eff9aa1 100644 --- a/util/src/journaldb/overlay.rs +++ b/util/src/journaldb/overlay.rs @@ -33,14 +33,14 @@ use super::JournalDB; /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. /// -/// There are two memory overlays: -/// - Transaction overlay contains current transaction data. It is merged with with history +/// There are two memory overlays: +/// - Transaction overlay contains current transaction data. It is merged with with history /// overlay on each `commit()` -/// - History overlay contains all data inserted during the history period. When the node +/// - History overlay contains all data inserted during the history period. When the node /// in the overlay becomes ancient it is written to disk on `commit()` /// -/// There is also a journal maintained in memory and on the disk as well which lists insertions -/// and removals for each commit during the history period. This is used to track +/// There is also a journal maintained in memory and on the disk as well which lists insertions +/// and removals for each commit during the history period. This is used to track /// data nodes that go out of history scope and must be written to disk. /// /// Commit workflow: @@ -50,12 +50,12 @@ use super::JournalDB; /// 3. Clear the transaction overlay. /// 4. For a canonical journal record that becomes ancient inserts its insertions into the disk DB /// 5. For each journal record that goes out of the history scope (becomes ancient) remove its -/// insertions from the history overlay, decreasing the reference counter and removing entry if +/// insertions from the history overlay, decreasing the reference counter and removing entry if /// if reaches zero. -/// 6. For a canonical journal record that becomes ancient delete its removals from the disk only if +/// 6. For a canonical journal record that becomes ancient delete its removals from the disk only if /// the removed key is not present in the history overlay. /// 7. Delete ancient record from memory and disk. -/// +/// pub struct JournalOverlayDB { transaction_overlay: MemoryDB, backing: Arc, @@ -223,7 +223,7 @@ impl JournalDB for JournalOverlayDB { let mut tx = self.transaction_overlay.drain(); let inserted_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c > 0 { Some(k.clone()) } else { None }).collect(); let removed_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c < 0 { Some(k.clone()) } else { None }).collect(); - // Increase counter for each inserted key no matter if the block is canonical or not. + // Increase counter for each inserted key no matter if the block is canonical or not. let insertions = tx.drain().filter_map(|(k, (v, c))| if c > 0 { Some((k, v)) } else { None }); r.append(id); r.begin_list(inserted_keys.len()); @@ -236,7 +236,7 @@ impl JournalDB for JournalOverlayDB { r.append(&removed_keys); let mut k = RlpStream::new_list(3); - let index = journal_overlay.journal.get(&now).map(|j| j.len()).unwrap_or(0); + let index = journal_overlay.journal.get(&now).map_or(0, |j| j.len()); k.append(&now); k.append(&index); k.append(&&PADDING[..]); @@ -345,14 +345,14 @@ impl HashDB for JournalOverlayDB { self.lookup(key).is_some() } - fn insert(&mut self, value: &[u8]) -> H256 { + fn insert(&mut self, value: &[u8]) -> H256 { self.transaction_overlay.insert(value) } fn emplace(&mut self, key: H256, value: Bytes) { - self.transaction_overlay.emplace(key, value); + self.transaction_overlay.emplace(key, value); } - fn kill(&mut self, key: &H256) { - self.transaction_overlay.kill(key); + fn kill(&mut self, key: &H256) { + self.transaction_overlay.kill(key); } } @@ -749,7 +749,7 @@ mod tests { assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); } - + #[test] fn reopen_test() { let mut dir = ::std::env::temp_dir(); @@ -784,7 +784,7 @@ mod tests { jdb.commit(7, &b"7".sha3(), Some((3, b"3".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); } - + #[test] fn reopen_remove_three() { init_log(); @@ -838,7 +838,7 @@ mod tests { assert!(!jdb.exists(&foo)); } } - + #[test] fn reopen_fork() { let mut dir = ::std::env::temp_dir(); From 65dadcc2a2bfe9c5d382b2d2716fee857318cf68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 12 Mar 2016 10:44:24 +0100 Subject: [PATCH 540/753] Adding todos --- ethcore/src/client/client.rs | 5 ++--- ethcore/src/client/mod.rs | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 4341e1898..1a88af951 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -350,16 +350,15 @@ impl Client where V: Verifier { } } - -// TODO: need MinerService MinerIoHandler - impl BlockChainClient for Client where V: Verifier { + // TODO [todr] Should be moved to miner crate eventually. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result { block.try_seal(self.engine.deref().deref(), seal) } + // TODO [todr] Should be moved to miner crate eventually. fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option { let engine = self.engine.deref().deref(); let h = self.chain.best_block_hash(); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index d97f0d8b9..c13cfeee1 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -102,9 +102,11 @@ pub trait BlockChainClient : Sync + Send { /// Returns logs matching given filter. fn logs(&self, filter: Filter) -> Vec; + // TODO [todr] Should be moved to miner crate eventually. /// Returns ClosedBlock prepared for sealing. fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option; + // TODO [todr] Should be moved to miner crate eventually. /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result; From e1c0177932efef0b75c58e2e9ce3058eeb2a40cd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 10:44:48 +0100 Subject: [PATCH 541/753] Update main.rs --- parity/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 9e6b50e08..1350aca45 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -248,8 +248,14 @@ fn setup_rpc_server( #[cfg(not(feature = "rpc"))] fn setup_rpc_server( - _client: Arc, _sync: Arc, _secret_store: Arc, _miner: Arc, - _url: &str, _cors_domain: &str, _apis: Vec<&str>) -> Option> { + _client: Arc, + _sync: Arc, + _secret_store: Arc, + _miner: Arc, + _url: &str, + _cors_domain: &str, + _apis: Vec<&str> +) -> Option> { None } From d7039b72e237fb739dc98e344aa06ebf8cd49028 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 10:48:28 +0100 Subject: [PATCH 542/753] Update archivedb.rs --- util/src/journaldb/archivedb.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index c8c29e765..8db239cff 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -305,7 +305,6 @@ mod tests { assert!(jdb.exists(&foo)); } - #[test] fn reopen() { let mut dir = ::std::env::temp_dir(); @@ -364,6 +363,7 @@ mod tests { jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); } } + #[test] fn reopen_fork() { let mut dir = ::std::env::temp_dir(); @@ -406,6 +406,5 @@ mod tests { let state = jdb.state(&key); assert!(state.is_some()); } - } } From 82a881005740f2e1ddc2f862b2f617b3e5773597 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 11:19:42 +0100 Subject: [PATCH 543/753] Rename into something that is a little more descriptive. --- .../{optiononedb.rs => earlymergedb.rs} | 48 +++++++------- util/src/journaldb/mod.rs | 8 +-- .../{overlay.rs => overlayrecentdb.rs} | 66 +++++++++---------- 3 files changed, 61 insertions(+), 61 deletions(-) rename util/src/journaldb/{optiononedb.rs => earlymergedb.rs} (94%) rename util/src/journaldb/{overlay.rs => overlayrecentdb.rs} (93%) diff --git a/util/src/journaldb/optiononedb.rs b/util/src/journaldb/earlymergedb.rs similarity index 94% rename from util/src/journaldb/optiononedb.rs rename to util/src/journaldb/earlymergedb.rs index dfa7c8ec1..48083f113 100644 --- a/util/src/journaldb/optiononedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -32,7 +32,7 @@ use std::env; /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. -pub struct OptionOneDB { +pub struct EarlyMergeDB { overlay: MemoryDB, backing: Arc, counters: Option>>>, @@ -44,9 +44,9 @@ const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 const DB_VERSION : u32 = 3; const PADDING : [u8; 10] = [ 0u8; 10 ]; -impl OptionOneDB { +impl EarlyMergeDB { /// Create a new instance from file - pub fn new(path: &str) -> OptionOneDB { + pub fn new(path: &str) -> EarlyMergeDB { let opts = DatabaseConfig { prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix }; @@ -62,8 +62,8 @@ impl OptionOneDB { backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } - let counters = Some(Arc::new(RwLock::new(OptionOneDB::read_counters(&backing)))); - OptionOneDB { + let counters = Some(Arc::new(RwLock::new(EarlyMergeDB::read_counters(&backing)))); + EarlyMergeDB { overlay: MemoryDB::new(), backing: Arc::new(backing), counters: counters, @@ -72,7 +72,7 @@ impl OptionOneDB { /// Create a new instance with an anonymous temporary database. #[cfg(test)] - fn new_temp() -> OptionOneDB { + fn new_temp() -> EarlyMergeDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); Self::new(dir.to_str().unwrap()) @@ -193,7 +193,7 @@ impl OptionOneDB { } } -impl HashDB for OptionOneDB { +impl HashDB for EarlyMergeDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter() { @@ -238,9 +238,9 @@ impl HashDB for OptionOneDB { } } -impl JournalDB for OptionOneDB { +impl JournalDB for EarlyMergeDB { fn spawn(&self) -> Box { - Box::new(OptionOneDB { + Box::new(EarlyMergeDB { overlay: MemoryDB::new(), backing: self.backing.clone(), counters: self.counters.clone(), @@ -369,11 +369,11 @@ impl JournalDB for OptionOneDB { try!(batch.delete(&last)); index += 1; } - trace!("OptionOneDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); + trace!("EarlyMergeDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); } try!(self.backing.write(batch)); -// trace!("OptionOneDB::commit() deleted {} nodes", deletes); +// trace!("EarlyMergeDB::commit() deleted {} nodes", deletes); Ok(0) } } @@ -388,7 +388,7 @@ mod tests { #[test] fn insert_same_in_fork() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = EarlyMergeDB::new_temp(); let x = jdb.insert(b"X"); jdb.commit(1, &b"1".sha3(), None).unwrap(); @@ -410,7 +410,7 @@ mod tests { #[test] fn long_history() { // history is 3 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = EarlyMergeDB::new_temp(); let h = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.exists(&h)); @@ -428,7 +428,7 @@ mod tests { #[test] fn complex() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = EarlyMergeDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -466,7 +466,7 @@ mod tests { #[test] fn fork() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = EarlyMergeDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -494,7 +494,7 @@ mod tests { #[test] fn overwrite() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = EarlyMergeDB::new_temp(); let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -513,7 +513,7 @@ mod tests { #[test] fn fork_same_key() { // history is 1 - let mut jdb = OptionOneDB::new_temp(); + let mut jdb = EarlyMergeDB::new_temp(); jdb.commit(0, &b"0".sha3(), None).unwrap(); let foo = jdb.insert(b"foo"); @@ -535,7 +535,7 @@ mod tests { let bar = H256::random(); let foo = { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.emplace(bar.clone(), b"bar".to_vec()); @@ -544,13 +544,13 @@ mod tests { }; { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); } { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); @@ -564,7 +564,7 @@ mod tests { dir.push(H32::random().hex()); let foo = { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -578,7 +578,7 @@ mod tests { }; { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); assert!(jdb.exists(&foo)); @@ -593,7 +593,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); let (foo, bar, baz) = { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -608,7 +608,7 @@ mod tests { }; { - let mut jdb = OptionOneDB::new(dir.to_str().unwrap()); + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); assert!(jdb.exists(&foo)); assert!(!jdb.exists(&baz)); diff --git a/util/src/journaldb/mod.rs b/util/src/journaldb/mod.rs index cf8e7d392..724e61dfb 100644 --- a/util/src/journaldb/mod.rs +++ b/util/src/journaldb/mod.rs @@ -21,8 +21,8 @@ use common::*; /// Export the journaldb module. pub mod traits; mod archivedb; -mod optiononedb; -mod overlay; +mod earlymergedb; +mod overlayrecentdb; /// Export the JournalDB trait. pub use self::traits::JournalDB; @@ -73,8 +73,8 @@ impl fmt::Display for Algorithm { pub fn new(path: &str, algorithm: Algorithm) -> Box { match algorithm { Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)), - Algorithm::EarlyMerge => Box::new(optiononedb::OptionOneDB::new(path)), - Algorithm::OverlayRecent => Box::new(overlay::JournalOverlayDB::new(path)), + Algorithm::EarlyMerge => Box::new(optiononedb::EarlyMergeDB::new(path)), + Algorithm::OverlayRecent => Box::new(optiononedb::OverlayRecentDB::new(path)), _ => unimplemented!(), } } diff --git a/util/src/journaldb/overlay.rs b/util/src/journaldb/overlayrecentdb.rs similarity index 93% rename from util/src/journaldb/overlay.rs rename to util/src/journaldb/overlayrecentdb.rs index e91709041..8dd4d1752 100644 --- a/util/src/journaldb/overlay.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -56,7 +56,7 @@ use super::JournalDB; /// the removed key is not present in the history overlay. /// 7. Delete ancient record from memory and disk. /// -pub struct JournalOverlayDB { +pub struct OverlayRecentDB { transaction_overlay: MemoryDB, backing: Arc, journal_overlay: Arc>, @@ -82,9 +82,9 @@ impl HeapSizeOf for JournalEntry { } } -impl Clone for JournalOverlayDB { - fn clone(&self) -> JournalOverlayDB { - JournalOverlayDB { +impl Clone for OverlayRecentDB { + fn clone(&self) -> OverlayRecentDB { + OverlayRecentDB { transaction_overlay: MemoryDB::new(), backing: self.backing.clone(), journal_overlay: self.journal_overlay.clone(), @@ -98,14 +98,14 @@ const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 const DB_VERSION : u32 = 0x200 + 3; const PADDING : [u8; 10] = [ 0u8; 10 ]; -impl JournalOverlayDB { +impl OverlayRecentDB { /// Create a new instance from file - pub fn new(path: &str) -> JournalOverlayDB { + pub fn new(path: &str) -> OverlayRecentDB { Self::from_prefs(path) } /// Create a new instance from file - pub fn from_prefs(path: &str) -> JournalOverlayDB { + pub fn from_prefs(path: &str) -> OverlayRecentDB { let opts = DatabaseConfig { prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix }; @@ -121,8 +121,8 @@ impl JournalOverlayDB { backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } - let journal_overlay = Arc::new(RwLock::new(JournalOverlayDB::read_overlay(&backing))); - JournalOverlayDB { + let journal_overlay = Arc::new(RwLock::new(OverlayRecentDB::read_overlay(&backing))); + OverlayRecentDB { transaction_overlay: MemoryDB::new(), backing: Arc::new(backing), journal_overlay: journal_overlay, @@ -131,7 +131,7 @@ impl JournalOverlayDB { /// Create a new instance with an anonymous temporary database. #[cfg(test)] - pub fn new_temp() -> JournalOverlayDB { + pub fn new_temp() -> OverlayRecentDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); Self::new(dir.to_str().unwrap()) @@ -196,7 +196,7 @@ impl JournalOverlayDB { } } -impl JournalDB for JournalOverlayDB { +impl JournalDB for OverlayRecentDB { fn spawn(&self) -> Box { Box::new(self.clone()) } @@ -303,7 +303,7 @@ impl JournalDB for JournalOverlayDB { } -impl HashDB for JournalOverlayDB { +impl HashDB for OverlayRecentDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter() { @@ -367,7 +367,7 @@ mod tests { #[test] fn insert_same_in_fork() { // history is 1 - let mut jdb = JournalOverlayDB::new_temp(); + let mut jdb = OverlayRecentDB::new_temp(); let x = jdb.insert(b"X"); jdb.commit(1, &b"1".sha3(), None).unwrap(); @@ -397,7 +397,7 @@ mod tests { #[test] fn long_history() { // history is 3 - let mut jdb = JournalOverlayDB::new_temp(); + let mut jdb = OverlayRecentDB::new_temp(); let h = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -420,7 +420,7 @@ mod tests { #[test] fn complex() { // history is 1 - let mut jdb = JournalOverlayDB::new_temp(); + let mut jdb = OverlayRecentDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -463,7 +463,7 @@ mod tests { #[test] fn fork() { // history is 1 - let mut jdb = JournalOverlayDB::new_temp(); + let mut jdb = OverlayRecentDB::new_temp(); let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -495,7 +495,7 @@ mod tests { #[test] fn overwrite() { // history is 1 - let mut jdb = JournalOverlayDB::new_temp(); + let mut jdb = OverlayRecentDB::new_temp(); let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -520,7 +520,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -548,7 +548,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -576,7 +576,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.commit(0, &b"0".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -614,7 +614,7 @@ mod tests { let bar = H256::random(); let foo = { - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.emplace(bar.clone(), b"bar".to_vec()); @@ -624,14 +624,14 @@ mod tests { }; { - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); } { - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); @@ -646,7 +646,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); // history is 4 let foo = jdb.insert(b"foo"); @@ -675,7 +675,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); // history is 4 let foo = jdb.insert(b"foo"); @@ -724,7 +724,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); @@ -755,7 +755,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); // history is 4 let foo = jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -795,7 +795,7 @@ mod tests { let foo = b"foo".sha3(); { - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); // history is 1 jdb.insert(b"foo"); jdb.commit(0, &b"0".sha3(), None).unwrap(); @@ -816,7 +816,7 @@ mod tests { assert!(jdb.exists(&foo)); // incantation to reopen the db - }; { let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + }; { let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.remove(&foo); jdb.commit(4, &b"4".sha3(), Some((2, b"2".sha3()))).unwrap(); @@ -824,14 +824,14 @@ mod tests { assert!(jdb.exists(&foo)); // incantation to reopen the db - }; { let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + }; { let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.commit(5, &b"5".sha3(), Some((3, b"3".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); // incantation to reopen the db - }; { let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + }; { let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.commit(6, &b"6".sha3(), Some((4, b"4".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); @@ -844,7 +844,7 @@ mod tests { let mut dir = ::std::env::temp_dir(); dir.push(H32::random().hex()); let (foo, bar, baz) = { - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); // history is 1 let foo = jdb.insert(b"foo"); let bar = jdb.insert(b"bar"); @@ -862,7 +862,7 @@ mod tests { }; { - let mut jdb = JournalOverlayDB::new(dir.to_str().unwrap()); + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); assert!(jdb.exists(&foo)); From b03679e1a6e8f29dee36b0bfe3a4c701a7f154e4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 11:22:02 +0100 Subject: [PATCH 544/753] Fix typos. --- util/src/journaldb/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/journaldb/mod.rs b/util/src/journaldb/mod.rs index 724e61dfb..cf5278368 100644 --- a/util/src/journaldb/mod.rs +++ b/util/src/journaldb/mod.rs @@ -73,8 +73,8 @@ impl fmt::Display for Algorithm { pub fn new(path: &str, algorithm: Algorithm) -> Box { match algorithm { Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)), - Algorithm::EarlyMerge => Box::new(optiononedb::EarlyMergeDB::new(path)), - Algorithm::OverlayRecent => Box::new(optiononedb::OverlayRecentDB::new(path)), + Algorithm::EarlyMerge => Box::new(earlymergedb::EarlyMergeDB::new(path)), + Algorithm::OverlayRecent => Box::new(overlayrecentdb::OverlayRecentDB::new(path)), _ => unimplemented!(), } } From 98bae098bea3b5a6db3fd891eba4e54ce8e3645e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 12:10:55 +0100 Subject: [PATCH 545/753] Update cargo lock. --- Cargo.lock | 88 +++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f26ac923..8e3a4b168 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,7 +31,7 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -43,14 +43,14 @@ name = "aster" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bigint" version = "0.1.0" dependencies = [ - "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -85,7 +85,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chrono" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -117,7 +117,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -136,7 +136,7 @@ version = "1.1.1" source = "git+https://github.com/tomusdrw/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -145,7 +145,7 @@ name = "daemonize" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -161,7 +161,7 @@ name = "docopt" version = "0.6.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -177,7 +177,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -185,7 +185,7 @@ name = "eth-secp256k1" version = "0.5.4" source = "git+https://github.com/ethcore/rust-secp256k1#283a0677d8327536be58a87e0494d7e0e7b1d1d8" dependencies = [ - "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -253,9 +253,9 @@ dependencies = [ name = "ethcore-util" version = "0.9.99" dependencies = [ - "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", - "chrono 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -264,10 +264,10 @@ dependencies = [ "ethcore-devtools 0.9.99", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -304,7 +304,7 @@ dependencies = [ name = "fdlimit" version = "0.1.0" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -314,7 +314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "glob" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -328,7 +328,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -381,7 +381,7 @@ dependencies = [ "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -391,21 +391,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itertools" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "json-tests" version = "0.1.0" dependencies = [ - "glob 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -461,7 +461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -469,7 +469,7 @@ name = "librocksdb-sys" version = "0.2.2" source = "git+https://github.com/arkpar/rust-rocksdb.git#a4f89fea20ee3ae92b692df65d56426a5c0b6fd5" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -477,7 +477,7 @@ name = "log" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -490,7 +490,7 @@ name = "memchr" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -536,7 +536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -560,7 +560,7 @@ dependencies = [ [[package]] name = "nom" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -577,7 +577,7 @@ name = "num_cpus" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -639,7 +639,7 @@ name = "quasi" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -649,7 +649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -657,7 +657,7 @@ name = "rand" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -672,7 +672,7 @@ dependencies = [ [[package]] name = "regex" -version = "0.1.54" +version = "0.1.55" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -691,7 +691,7 @@ name = "rocksdb" version = "0.4.2" source = "git+https://github.com/arkpar/rust-rocksdb.git#a4f89fea20ee3ae92b692df65d56426a5c0b6fd5" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "librocksdb-sys 0.2.2 (git+https://github.com/arkpar/rust-rocksdb.git)", ] @@ -701,7 +701,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -741,7 +741,7 @@ name = "semver" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nom 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -766,7 +766,7 @@ dependencies = [ "quasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "quasi_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -809,16 +809,16 @@ name = "syntex" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syntex_syntax" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -844,7 +844,7 @@ name = "termios" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -853,7 +853,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -918,7 +918,7 @@ dependencies = [ [[package]] name = "url" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -975,7 +975,7 @@ name = "xml-rs" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] From 19b6c74675cbf96cb0118cb13e5279860d182876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 12 Mar 2016 13:39:17 +0100 Subject: [PATCH 546/753] Two more warnings --- ethcore/src/verification/noop_verifier.rs | 1 + parity/main.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/ethcore/src/verification/noop_verifier.rs b/ethcore/src/verification/noop_verifier.rs index ae2a153fe..20c15c3f1 100644 --- a/ethcore/src/verification/noop_verifier.rs +++ b/ethcore/src/verification/noop_verifier.rs @@ -20,6 +20,7 @@ use error::Error; use header::Header; use super::Verifier; +#[allow(dead_code)] pub struct NoopVerifier; impl Verifier for NoopVerifier { diff --git a/parity/main.rs b/parity/main.rs index 3770fe04d..b16801ad5 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -394,6 +394,7 @@ impl Configuration { } } + #[cfg_attr(feature="dev", allow(useless_format))] fn execute_client(&self) { // Setup panic handler let panic_handler = PanicHandler::new_in_arc(); From 451a5d78e35da7da15c44945375083322fe6b013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 12 Mar 2016 13:40:39 +0100 Subject: [PATCH 547/753] Removing unused (?) serde::Error --- rpc/src/v1/types/transaction.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 0518a58ea..232cf0bf3 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -17,7 +17,6 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; -use serde::Error; #[derive(Debug, Default, Serialize)] pub struct Transaction { From 7ad7996144cc3f3cbf982f0d78af25be2f1c2846 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 11 Mar 2016 18:50:29 +0100 Subject: [PATCH 548/753] Fixed common block detection --- sync/src/chain.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 4a2d941a7..5ba2e8773 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -377,10 +377,14 @@ impl ChainSync { let hash = info.hash(); match io.chain().block_status(BlockId::Hash(hash.clone())) { BlockStatus::InChain => { - self.have_common_block = true; - self.last_imported_block = Some(number); - self.last_imported_hash = Some(hash.clone()); - trace!(target: "sync", "Found common header {} ({})", number, hash); + if !self.have_common_block { + self.have_common_block = true; + self.last_imported_block = Some(number); + self.last_imported_hash = Some(hash.clone()); + trace!(target: "sync", "Found common header {} ({})", number, hash); + } else { + trace!(target: "sync", "Header already in chain {} ({})", number, hash); + } }, _ => { if self.have_common_block { From 1fe575bf7bbdf276c1f3f8242d278fc1a573a099 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 11 Mar 2016 20:17:36 +0100 Subject: [PATCH 549/753] Download bodies for validated hash chain only --- sync/src/chain.rs | 19 +++---------------- sync/src/range_collection.rs | 11 ++++++++--- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 5ba2e8773..657ef6a78 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -660,10 +660,7 @@ impl ChainSync { let mut needed_numbers: Vec = Vec::new(); if self.have_common_block && !self.headers.is_empty() && self.headers.range_iter().next().unwrap().0 == self.current_base_block() + 1 { - for (start, ref items) in self.headers.range_iter() { - if needed_bodies.len() >= MAX_BODIES_TO_REQUEST { - break; - } + if let Some((start, ref items)) = self.headers.range_iter().next() { let mut index: BlockNumber = 0; while index != items.len() as BlockNumber && needed_bodies.len() < MAX_BODIES_TO_REQUEST { let block = start + index; @@ -848,18 +845,8 @@ impl ChainSync { /// Remove downloaded bocks/headers starting from specified number. /// Used to recover from an error and re-download parts of the chain detected as bad. fn remove_downloaded_blocks(&mut self, start: BlockNumber) { - for n in self.headers.get_tail(&start) { - if let Some(ref header_data) = self.headers.find_item(&n) { - let header_to_delete = HeaderView::new(&header_data.data); - let header_id = HeaderId { - transactions_root: header_to_delete.transactions_root(), - uncles: header_to_delete.uncles_hash() - }; - self.header_ids.remove(&header_id); - } - self.downloading_bodies.remove(&n); - self.downloading_headers.remove(&n); - } + self.downloading_bodies.clear(); + self.downloading_headers.clear(); self.headers.remove_from(&start); self.bodies.remove_from(&start); } diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index 664d7c7a3..0628df401 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -300,12 +300,17 @@ fn test_range() { let mut r = ranges.clone(); r.remove_from(&20); assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal); - r.remove_from(&17); - assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p'][..])]), Ordering::Equal); - r.remove_from(&15); + r.remove_from(&18); + assert!(!r.have_item(&18)); + assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q'][..])]), Ordering::Equal); + r.remove_from(&16); + assert!(!r.have_item(&16)); assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..])]), Ordering::Equal); r.remove_from(&3); assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal); + r.remove_from(&1); + assert_eq!(r.range_iter().next(), None); + let mut r = ranges.clone(); r.remove_from(&2); assert_eq!(r.range_iter().next(), None); } From 16618094f5211ad26d83e2ef2c7cb57420c48388 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 11 Mar 2016 21:23:36 +0100 Subject: [PATCH 550/753] Cleanup header_ids --- sync/src/chain.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 657ef6a78..a30db0423 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -377,10 +377,12 @@ impl ChainSync { let hash = info.hash(); match io.chain().block_status(BlockId::Hash(hash.clone())) { BlockStatus::InChain => { - if !self.have_common_block { - self.have_common_block = true; + if self.current_base_block() < number { self.last_imported_block = Some(number); self.last_imported_hash = Some(hash.clone()); + } + if !self.have_common_block { + self.have_common_block = true; trace!(target: "sync", "Found common header {} ({})", number, hash); } else { trace!(target: "sync", "Header already in chain {} ({})", number, hash); @@ -845,8 +847,12 @@ impl ChainSync { /// Remove downloaded bocks/headers starting from specified number. /// Used to recover from an error and re-download parts of the chain detected as bad. fn remove_downloaded_blocks(&mut self, start: BlockNumber) { - self.downloading_bodies.clear(); - self.downloading_headers.clear(); + let ids = self.header_ids.drain().filter(|&(_, v)| v < start).collect(); + self.header_ids = ids; + let hdrs = self.downloading_headers.drain().filter(|v| *v < start).collect(); + self.downloading_headers = hdrs; + let bodies = self.downloading_bodies.drain().filter(|v| *v < start).collect(); + self.downloading_bodies = bodies; self.headers.remove_from(&start); self.bodies.remove_from(&start); } From 1e23a4c888c9feab5c8343e1f2c49a953f560cb8 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 12 Mar 2016 14:54:44 +0100 Subject: [PATCH 551/753] Don't redownload queued blocks on restart --- sync/src/chain.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index a30db0423..84ca5500a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -298,8 +298,6 @@ impl ChainSync { /// Restart sync pub fn restart(&mut self, io: &mut SyncIo) { self.reset(); - self.last_imported_block = None; - self.last_imported_hash = None; self.starting_block = 0; self.highest_block = None; self.have_common_block = false; @@ -366,7 +364,7 @@ impl ChainSync { for i in 0..item_count { let info: BlockHeader = try!(r.val_at(i)); let number = BlockNumber::from(info.number); - if number <= self.current_base_block() || self.headers.have_item(&number) { + if (number <= self.current_base_block() && self.have_common_block) || self.headers.have_item(&number) { trace!(target: "sync", "Skipping existing block header"); continue; } @@ -376,8 +374,8 @@ impl ChainSync { } let hash = info.hash(); match io.chain().block_status(BlockId::Hash(hash.clone())) { - BlockStatus::InChain => { - if self.current_base_block() < number { + BlockStatus::InChain | BlockStatus::Queued => { + if !self.have_common_block || self.current_base_block() < number { self.last_imported_block = Some(number); self.last_imported_hash = Some(hash.clone()); } @@ -706,7 +704,10 @@ impl ChainSync { if !self.have_common_block { // download backwards until common block is found 1 header at a time let chain_info = io.chain().chain_info(); - start = chain_info.best_block_number; + start = match self.last_imported_block { + Some(n) => n, + None => chain_info.best_block_number, + }; if !self.headers.is_empty() { start = min(start, self.headers.range_iter().next().unwrap().0 - 1); } From 1ca7c35c19adffe3775d137698d8da67362e093f Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 12 Mar 2016 17:30:46 +0100 Subject: [PATCH 552/753] Fix latest era marker --- util/src/journaldb/earlymergedb.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index 83be31fb4..f411691d9 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -64,6 +64,7 @@ pub struct EarlyMergeDB { overlay: MemoryDB, backing: Arc, refs: Option>>>, + latest_era: u64, } // all keys must be at least 12 bytes @@ -90,11 +91,13 @@ impl EarlyMergeDB { backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } - let refs = Some(Arc::new(RwLock::new(EarlyMergeDB::read_refs(&backing)))); + let (latest_era, refs) = EarlyMergeDB::read_refs(&backing); + let refs = Some(Arc::new(RwLock::new(refs))); EarlyMergeDB { overlay: MemoryDB::new(), backing: Arc::new(backing), refs: refs, + latest_era: latest_era, } } @@ -225,9 +228,9 @@ impl EarlyMergeDB { #[cfg(test)] fn can_reconstruct_refs(&self) -> bool { - let reconstructed = Self::read_refs(&self.backing); + let (latest_era, reconstructed) = Self::read_refs(&self.backing); let refs = self.refs.as_ref().unwrap().write().unwrap(); - if *refs != reconstructed { + if *refs != reconstructed || latest_era != self.latest_era { let clean_refs = refs.iter().filter_map(|(k, v)| if reconstructed.get(k) == Some(v) {None} else {Some((k.clone(), v.clone()))}).collect::>(); let clean_recon = reconstructed.into_iter().filter_map(|(k, v)| if refs.get(&k) == Some(&v) {None} else {Some((k.clone(), v.clone()))}).collect::>(); warn!(target: "jdb", "mem: {:?} != log: {:?}", clean_refs, clean_recon); @@ -241,10 +244,12 @@ impl EarlyMergeDB { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } - fn read_refs(db: &Database) -> HashMap { + fn read_refs(db: &Database) -> (u64, HashMap) { let mut refs = HashMap::new(); + let mut latest_era = 0u64; if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); + latest_era = decode::(&val); + let mut era = latest_era; loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ @@ -265,7 +270,7 @@ impl EarlyMergeDB { era -= 1; } } - refs + (latest_era, refs) } } @@ -320,6 +325,7 @@ impl JournalDB for EarlyMergeDB { overlay: MemoryDB::new(), backing: self.backing.clone(), refs: self.refs.clone(), + latest_era: self.latest_era, }) } @@ -435,7 +441,10 @@ impl JournalDB for EarlyMergeDB { trace!(target: "jdb.ops", " Deletes: {:?}", removes); } try!(batch.put(&last, r.as_raw())); - try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + if now >= self.latest_era { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + self.latest_era = now; + } } // apply old commits' details From 0b4355d549d30a03287543d95b2a482ccbe1687b Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 12 Mar 2016 19:03:33 +0100 Subject: [PATCH 553/753] rocksdb version bump --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e3a4b168..1c58cd431 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -271,7 +271,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.4.2 (git+https://github.com/arkpar/rust-rocksdb.git)", + "rocksdb 0.4.3 (git+https://github.com/arkpar/rust-rocksdb.git)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -466,8 +466,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librocksdb-sys" -version = "0.2.2" -source = "git+https://github.com/arkpar/rust-rocksdb.git#a4f89fea20ee3ae92b692df65d56426a5c0b6fd5" +version = "0.2.3" +source = "git+https://github.com/arkpar/rust-rocksdb.git#ebb602fc74b4067f9f51310bdc0401b8e59b7156" dependencies = [ "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -688,11 +688,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" -version = "0.4.2" -source = "git+https://github.com/arkpar/rust-rocksdb.git#a4f89fea20ee3ae92b692df65d56426a5c0b6fd5" +version = "0.4.3" +source = "git+https://github.com/arkpar/rust-rocksdb.git#ebb602fc74b4067f9f51310bdc0401b8e59b7156" dependencies = [ "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "librocksdb-sys 0.2.2 (git+https://github.com/arkpar/rust-rocksdb.git)", + "librocksdb-sys 0.2.3 (git+https://github.com/arkpar/rust-rocksdb.git)", ] [[package]] From 89986ec0e0d38ca3385cdc6cfeecaa6c2115ff61 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 19:19:16 +0100 Subject: [PATCH 554/753] Update main.rs [noci] --- parity/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 1350aca45..a22e4f763 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -224,8 +224,14 @@ fn setup_log(init: &Option) { #[cfg(feature = "rpc")] fn setup_rpc_server( - client: Arc, sync: Arc, secret_store: Arc, miner: Arc, - url: &str, cors_domain: &str, apis: Vec<&str>) -> Option> { + client: Arc, + sync: Arc, + secret_store: Arc, + miner: Arc, + url: &str, + cors_domain: &str, + apis: Vec<&str> +) -> Option> { use rpc::v1::*; let server = rpc::RpcServer::new(); From 707f67c6b4b588e43af86adad2f64d9299d8e3e8 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 12 Mar 2016 19:19:45 +0100 Subject: [PATCH 555/753] Optional last era --- util/src/journaldb/earlymergedb.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index f411691d9..0931d42d1 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -64,7 +64,7 @@ pub struct EarlyMergeDB { overlay: MemoryDB, backing: Arc, refs: Option>>>, - latest_era: u64, + latest_era: Option, } // all keys must be at least 12 bytes @@ -244,12 +244,12 @@ impl EarlyMergeDB { self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) } - fn read_refs(db: &Database) -> (u64, HashMap) { + fn read_refs(db: &Database) -> (Option, HashMap) { let mut refs = HashMap::new(); - let mut latest_era = 0u64; + let mut latest_era = None; if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - latest_era = decode::(&val); - let mut era = latest_era; + let mut era = decode::(&val); + latest_era = Some(era); loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ @@ -325,7 +325,7 @@ impl JournalDB for EarlyMergeDB { overlay: MemoryDB::new(), backing: self.backing.clone(), refs: self.refs.clone(), - latest_era: self.latest_era, + latest_era: self.latest_era.clone(), }) } @@ -441,9 +441,9 @@ impl JournalDB for EarlyMergeDB { trace!(target: "jdb.ops", " Deletes: {:?}", removes); } try!(batch.put(&last, r.as_raw())); - if now >= self.latest_era { + if self.latest_era.map_or(true, |e| now > e) { try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); - self.latest_era = now; + self.latest_era = Some(now); } } From a9a1c80fac13732e9cd642822f768e2884663aac Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 12 Mar 2016 19:21:08 +0100 Subject: [PATCH 556/753] implemented eth_accounts, fixed personal_accounts, added test account provider, tests for eth_accounts --- rpc/src/v1/impls/eth.rs | 8 ++ rpc/src/v1/impls/personal.rs | 7 +- rpc/src/v1/tests/eth.rs | 59 ++++++++++++++ rpc/src/v1/tests/helpers/account_provider.rs | 84 ++++++++++++++++++++ rpc/src/v1/tests/helpers/mod.rs | 2 + rpc/src/v1/tests/mod.rs | 1 + 6 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 rpc/src/v1/tests/eth.rs create mode 100644 rpc/src/v1/tests/helpers/account_provider.rs diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 38e363624..47b5471b3 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -155,6 +155,14 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: } } + fn accounts(&self, _: Params) -> Result { + let store = take_weak!(self.accounts); + match store.accounts() { + Ok(account_list) => to_value(&account_list), + Err(_) => Err(Error::internal_error()) + } + } + fn block_number(&self, params: Params) -> Result { match params { Params::None => to_value(&U256::from(take_weak!(self.client).chain_info().best_block_number)), diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index ce200244c..0cd3f0040 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -39,12 +39,7 @@ impl Personal for PersonalClient where A: AccountProvider + 'static { fn accounts(&self, _: Params) -> Result { let store = take_weak!(self.accounts); match store.accounts() { - Ok(account_list) => { - Ok(Value::Array(account_list.iter() - .map(|&account| Value::String(format!("{:?}", account))) - .collect::>()) - ) - } + Ok(account_list) => to_value(&account_list), Err(_) => Err(Error::internal_error()) } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs new file mode 100644 index 000000000..c36a9d172 --- /dev/null +++ b/rpc/src/v1/tests/eth.rs @@ -0,0 +1,59 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashMap; +use std::sync::Arc; +use jsonrpc_core::IoHandler; +use util::hash::{Address}; +use ethcore::client::{TestBlockChainClient, EachBlockWith}; +use v1::{Eth, EthClient}; +use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config}; + +fn blockchain_client() -> Arc { + let mut client = TestBlockChainClient::new(); + client.add_blocks(10, EachBlockWith::Nothing); + Arc::new(client) +} + +fn accounts_provider() -> Arc { + let mut accounts = HashMap::new(); + accounts.insert(Address::from(1), TestAccount::new("test")); + let ap = TestAccountProvider::new(accounts); + Arc::new(ap) +} + +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })) +} + +#[test] +fn rpc_eth_accounts() { + let client = blockchain_client(); + let sync = sync_provider(); + let ap = accounts_provider(); + + let eth = EthClient::new(&client, &sync, &ap).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(eth); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/tests/helpers/account_provider.rs b/rpc/src/v1/tests/helpers/account_provider.rs new file mode 100644 index 000000000..66f085f74 --- /dev/null +++ b/rpc/src/v1/tests/helpers/account_provider.rs @@ -0,0 +1,84 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::RwLock; +use std::collections::HashMap; +use std::io; +use util::hash::{Address, H256}; +use util::crypto::{Secret, Signature}; +use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError}; + +/// Account mock. +#[derive(Clone)] +pub struct TestAccount { + /// True if account is unlocked. + pub unlocked: bool, + /// Account's password. + pub password: String, +} + +impl TestAccount { + pub fn new(password: &str) -> Self { + TestAccount { + unlocked: false, + password: password.to_owned(), + } + } +} + +/// Test account provider. +pub struct TestAccountProvider { + accounts: RwLock>, +} + +impl TestAccountProvider { + /// Basic constructor. + pub fn new(accounts: HashMap) -> Self { + TestAccountProvider { + accounts: RwLock::new(accounts), + } + } +} + +impl AccountProvider for TestAccountProvider { + fn accounts(&self) -> Result, io::Error> { + Ok(self.accounts.read().unwrap().keys().cloned().collect()) + } + + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + match self.accounts.write().unwrap().get_mut(account) { + Some(ref mut acc) if acc.password == pass => { + acc.unlocked = true; + Ok(()) + }, + Some(_) => Err(EncryptedHashMapError::InvalidPassword), + None => Err(EncryptedHashMapError::UnknownIdentifier), + } + } + + fn new_account(&self, _pass: &str) -> Result { + unimplemented!() + } + fn account_secret(&self, _account: &Address) -> Result { + unimplemented!() + } + + fn sign(&self, _account: &Address, _message: &H256) -> Result { + unimplemented!() + } + +} + diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index 501bfb2d3..3bd74bab7 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +mod account_provider; mod sync_provider; +pub use self::account_provider::{TestAccount, TestAccountProvider}; pub use self::sync_provider::{Config, TestSyncProvider}; diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 3a38ced15..3374bad36 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -16,6 +16,7 @@ //!TODO: load custom blockchain state and test +mod eth; mod net; mod web3; mod helpers; From e85a2f3804dea8387181008ba86d1b3456bde555 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 19:22:38 +0100 Subject: [PATCH 557/753] Update main.rs [noci] --- parity/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index a22e4f763..93fed03aa 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -506,7 +506,9 @@ impl Configuration { sync.clone(), account_service.clone(), miner.clone(), - &url, cors, apis.split(',').collect() + &url, + cors, + apis.split(',').collect() ); if let Some(handler) = server_handler { panic_handler.forward_from(handler.deref()); From 0684abd345aa9405d59bda17bae868d319d48329 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 12 Mar 2016 19:23:17 +0100 Subject: [PATCH 558/753] fixed to return receipts grouped by requested block --- ethcore/src/client/test_client.rs | 5 +++-- sync/src/chain.rs | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 207f1090f..76e13fe9f 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -24,6 +24,7 @@ use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; use receipt::Receipt; +use extras::BlockReceipts; use error::{ImportResult, Error}; use block_queue::BlockQueueInfo; use block::ClosedBlock; @@ -254,10 +255,10 @@ impl BlockChainClient for TestBlockChainClient { fn block_receipts(&self, hash: &H256) -> Option { // starts with 'f' ? if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { - let receipt = Receipt::new( + let receipt = BlockReceipts::new(vec![Receipt::new( H256::zero(), U256::zero(), - vec![]); + vec![])]); let mut rlp = RlpStream::new(); rlp.append(&receipt); return Some(rlp.out()); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 4a2d941a7..ae4744902 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -66,6 +66,7 @@ const MAX_BODIES_TO_SEND: usize = 256; const MAX_HEADERS_TO_SEND: usize = 512; const MAX_NODE_DATA_TO_SEND: usize = 1024; const MAX_RECEIPTS_TO_SEND: usize = 1024; +const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 16; const MAX_HEADERS_TO_REQUEST: usize = 512; const MAX_BODIES_TO_REQUEST: usize = 256; const MIN_PEERS_PROPAGATION: usize = 4; @@ -1060,17 +1061,20 @@ impl ChainSync { debug!(target: "sync", "Empty GetReceipts request, ignoring."); return Ok(None); } - count = min(count, MAX_RECEIPTS_TO_SEND); - let mut added = 0usize; + count = min(count, MAX_RECEIPTS_HEADERS_TO_SEND); + let mut added_headers = 0usize; + let mut added_receipts = 0usize; let mut data = Bytes::new(); for i in 0..count { - if let Some(mut hdr) = io.chain().block_receipts(&try!(rlp.val_at::(i))) { - data.append(&mut hdr); - added += 1; + if let Some(mut receipts_bytes) = io.chain().block_receipts(&try!(rlp.val_at::(i))) { + data.append(&mut receipts_bytes); + added_receipts += receipts_bytes.len(); + added_headers += 1; + if added_receipts > MAX_RECEIPTS_TO_SEND { break; } } } - let mut rlp_result = RlpStream::new_list(added); - rlp_result.append_raw(&data, added); + let mut rlp_result = RlpStream::new_list(added_headers); + rlp_result.append_raw(&data, added_headers); Ok(Some((RECEIPTS_PACKET, rlp_result))) } @@ -1396,7 +1400,7 @@ mod tests { assert!(rlp_result.is_some()); // the length of two rlp-encoded receipts - assert_eq!(597, rlp_result.unwrap().1.out().len()); + assert_eq!(603, rlp_result.unwrap().1.out().len()); let mut sync = dummy_sync_with_peer(H256::new()); io.sender = Some(2usize); From e7574d451675592f10fa23d0cf8afeb2ba758345 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 12 Mar 2016 19:29:18 +0100 Subject: [PATCH 559/753] Update lib.rs --- sync/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/src/lib.rs b/sync/src/lib.rs index bcf8fbcd1..0c7abd1d0 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -167,7 +167,7 @@ impl NetworkProtocolHandler for EthSync { #[allow(single_match)] fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { - SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted} => { + SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted } => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); self.sync.write().unwrap().chain_new_blocks(&mut sync_io, good, bad, retracted); }, From e09de6ea3d8877cb8926dff11b9cef644ae07506 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 12 Mar 2016 19:51:24 +0100 Subject: [PATCH 560/753] added missing eth_getBalance rpc method and tests for it --- ethcore/src/client/client.rs | 4 ++++ ethcore/src/client/mod.rs | 3 +++ ethcore/src/client/test_client.rs | 11 +++++++++++ rpc/src/v1/impls/eth.rs | 5 +++++ rpc/src/v1/tests/eth.rs | 25 ++++++++++++++++++++++++- rpc/src/v1/traits/eth.rs | 2 +- 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 4e8c34b33..a860dd752 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -449,6 +449,10 @@ impl BlockChainClient for Client where V: Verifier { self.state().code(address) } + fn balance(&self, address: &Address) -> U256 { + self.state().balance(address) + } + fn transaction(&self, id: TransactionId) -> Option { match id { TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index afdfb200a..af2c6ac14 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -66,6 +66,9 @@ pub trait BlockChainClient : Sync + Send { /// Get address code. fn code(&self, address: &Address) -> Option; + /// Get address balance. + fn balance(&self, address: &Address) -> U256; + /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 207f1090f..cf1352bc8 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -40,6 +40,8 @@ pub struct TestBlockChainClient { pub last_hash: RwLock, /// Difficulty. pub difficulty: RwLock, + /// Balances. + pub balances: RwLock>, } #[derive(Clone)] @@ -65,12 +67,17 @@ impl TestBlockChainClient { genesis_hash: H256::new(), last_hash: RwLock::new(H256::new()), difficulty: RwLock::new(From::from(0)), + balances: RwLock::new(HashMap::new()), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } + pub fn set_balance(&mut self, address: Address, balance: U256) { + self.balances.write().unwrap().insert(address, balance); + } + /// Add blocks to test client. pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { let len = self.numbers.read().unwrap().len(); @@ -165,6 +172,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn balance(&self, address: &Address) -> U256 { + self.balances.read().unwrap().get(address).cloned().unwrap_or_else(U256::zero) + } + fn transaction(&self, _id: TransactionId) -> Option { unimplemented!(); } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 47b5471b3..f5159f55f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -170,6 +170,11 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: } } + fn balance(&self, params: Params) -> Result { + from_params::<(Address, BlockNumber)>(params) + .and_then(|(address, _block_number)| to_value(&take_weak!(self.client).balance(&address))) + } + fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index c36a9d172..320d583d1 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -17,7 +17,8 @@ use std::collections::HashMap; use std::sync::Arc; use jsonrpc_core::IoHandler; -use util::hash::{Address}; +use util::hash::Address; +use util::numbers::U256; use ethcore::client::{TestBlockChainClient, EachBlockWith}; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config}; @@ -25,6 +26,7 @@ use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Con fn blockchain_client() -> Arc { let mut client = TestBlockChainClient::new(); client.add_blocks(10, EachBlockWith::Nothing); + client.set_balance(Address::from(1), U256::from(5)); Arc::new(client) } @@ -57,3 +59,24 @@ fn rpc_eth_accounts() { assert_eq!(io.handle_request(request), Some(response.to_owned())); } + +#[test] +fn rpc_eth_balance() { + let client = blockchain_client(); + let sync = sync_provider(); + let ap = accounts_provider(); + + let eth = EthClient::new(&client, &sync, &ap).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(eth); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0x0000000000000000000000000000000000000001", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x05","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 8c24dd38c..7d33cb63f 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -130,7 +130,7 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_gasPrice", Eth::gas_price); delegate.add_method("eth_accounts", Eth::accounts); delegate.add_method("eth_blockNumber", Eth::block_number); - delegate.add_method("eth_balance", Eth::balance); + delegate.add_method("eth_getBalance", Eth::balance); delegate.add_method("eth_getStorageAt", Eth::storage_at); delegate.add_method("eth_getTransactionCount", Eth::transaction_count); delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count_by_hash); From 361280a9bebb9b799effaf0689a26d7b2020a217 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 12 Mar 2016 19:52:37 +0100 Subject: [PATCH 561/753] Limit incoming connections --- util/src/network/host.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index f63c75e9f..57aae51d7 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -541,7 +541,7 @@ impl Host where Message: Send + Sync + Clone { match TcpStream::connect(&address) { Ok(socket) => socket, Err(e) => { - warn!("Can't connect to address {:?}: {:?}", address, e); + debug!("Can't connect to address {:?}: {:?}", address, e); return; } } @@ -695,6 +695,14 @@ impl Host where Message: Send + Sync + Clone { return; } }; + if !originated { + let session_count = sessions.count(); + let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; + if session_count >= ideal_peers as usize { + session.disconnect(DisconnectReason::TooManyPeers); + return; + } + } let result = sessions.insert_with(move |session_token| { session.set_token(session_token); io.deregister_stream(token).expect("Error deleting handshake registration"); From 49dd6661998689a7e373b98f706eb9bb14307252 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 12 Mar 2016 20:06:55 +0100 Subject: [PATCH 562/753] EthTester --- rpc/src/v1/tests/eth.rs | 44 ++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 320d583d1..8c61c2ed9 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -44,32 +44,40 @@ fn sync_provider() -> Arc { })) } +struct EthTester { + client: Arc, + sync: Arc, + accounts_provider: Arc, + pub io: IoHandler, +} + +impl Default for EthTester { + fn default() -> Self { + let client = blockchain_client(); + let sync = sync_provider(); + let ap = accounts_provider(); + let eth = EthClient::new(&client, &sync, &ap).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(eth); + EthTester { + client: client, + sync: sync, + accounts_provider: ap, + io: io + } + } +} + #[test] fn rpc_eth_accounts() { - let client = blockchain_client(); - let sync = sync_provider(); - let ap = accounts_provider(); - - let eth = EthClient::new(&client, &sync, &ap).to_delegate(); - let io = IoHandler::new(); - io.add_delegate(eth); - let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; - assert_eq!(io.handle_request(request), Some(response.to_owned())); + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } #[test] fn rpc_eth_balance() { - let client = blockchain_client(); - let sync = sync_provider(); - let ap = accounts_provider(); - - let eth = EthClient::new(&client, &sync, &ap).to_delegate(); - let io = IoHandler::new(); - io.add_delegate(eth); - let request = r#"{ "jsonrpc": "2.0", "method": "eth_getBalance", @@ -78,5 +86,5 @@ fn rpc_eth_balance() { }"#; let response = r#"{"jsonrpc":"2.0","result":"0x05","id":1}"#; - assert_eq!(io.handle_request(request), Some(response.to_owned())); + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } From 0a6fea1b77c58420d0014118786961770dcce713 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 13 Mar 2016 10:33:55 +0100 Subject: [PATCH 563/753] Silenced some non-important warnings --- sync/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 84ca5500a..332b78d83 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -592,7 +592,7 @@ impl ChainSync { pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { trace!(target: "sync", "== Connected {}", peer); if let Err(e) = self.send_status(io) { - warn!(target:"sync", "Error sending status request: {:?}", e); + debug!(target:"sync", "Error sending status request: {:?}", e); io.disable_peer(peer); } } @@ -1093,7 +1093,7 @@ impl ChainSync { let rlp = UntrustedRlp::new(data); if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) { - warn!(target:"sync", "Unexpected packet from unregistered peer: {}:{}", peer, io.peer_info(peer)); + debug!(target:"sync", "Unexpected packet from unregistered peer: {}:{}", peer, io.peer_info(peer)); return; } let result = match packet_id { From 0f21779ec4d5ea156437c0142cc21d5995f5e876 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 13 Mar 2016 11:06:57 +0100 Subject: [PATCH 564/753] make heavy --- util/src/keys/geth_import.rs | 1 + util/src/keys/store.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/util/src/keys/geth_import.rs b/util/src/keys/geth_import.rs index dbd9f0fe0..6c684c37d 100644 --- a/util/src/keys/geth_import.rs +++ b/util/src/keys/geth_import.rs @@ -161,6 +161,7 @@ mod tests { } #[test] + #[cfg(feature="heavy-tests")] fn can_decrypt_with_imported() { use keys::store::EncryptedHashMap; diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 6a5efc87d..f80d91123 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -363,6 +363,7 @@ mod vector_tests { #[test] + #[cfg(feature="heavy-tests")] fn mac_vector() { let password = "testpassword"; let salt = H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(); @@ -464,6 +465,7 @@ mod tests { } #[test] + #[cfg(feature="heavy-tests")] fn can_get() { let temp = RandomTempPath::create_dir(); let key_id = { From ff51d0fa676d1ebeca0648afc44e9bcbdd413dc5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 13 Mar 2016 11:50:09 +0100 Subject: [PATCH 565/753] Additional tests --- util/src/journaldb/earlymergedb.rs | 20 +++++++++++++++++ util/src/journaldb/overlayrecentdb.rs | 32 ++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index 0931d42d1..64c7fa69d 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -561,6 +561,26 @@ mod tests { assert!(jdb.exists(&x)); } + #[test] + fn insert_older_era() { + let mut jdb = EarlyMergeDB::new_temp(); + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let bar = jdb.insert(b"bar"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(0, &b"0b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"1".sha3(), Some((1, b"1".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + } + #[test] fn long_history() { // history is 3 diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index 8dd4d1752..36e8b68ad 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -66,7 +66,7 @@ pub struct OverlayRecentDB { struct JournalOverlay { backing_overlay: MemoryDB, journal: HashMap>, - latest_era: u64, + latest_era: Option, } #[derive(PartialEq)] @@ -152,10 +152,10 @@ impl OverlayRecentDB { let mut journal = HashMap::new(); let mut overlay = MemoryDB::new(); let mut count = 0; - let mut latest_era = 0; + let mut latest_era = None; if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - latest_era = decode::(&val); - let mut era = latest_era; + let mut era = decode::(&val); + latest_era = Some(era); loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ @@ -241,9 +241,9 @@ impl JournalDB for OverlayRecentDB { k.append(&index); k.append(&&PADDING[..]); try!(batch.put(&k.drain(), r.as_raw())); - if now >= journal_overlay.latest_era { + if journal_overlay.latest_era.map_or(true, |e| now > e) { try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); - journal_overlay.latest_era = now; + journal_overlay.latest_era = Some(now); } journal_overlay.journal.entry(now).or_insert_with(Vec::new).push(JournalEntry { id: id.clone(), insertions: inserted_keys, deletions: removed_keys }); } @@ -870,4 +870,24 @@ mod tests { assert!(!jdb.exists(&bar)); } } + + #[test] + fn insert_older_era() { + let mut jdb = OverlayRecentDB::new_temp(); + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let bar = jdb.insert(b"bar"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(0, &b"0b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"1".sha3(), Some((1, b"1".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + } } From 113161863060661f1b2afdf183f6bcfbb0706527 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 13 Mar 2016 11:55:48 +0100 Subject: [PATCH 566/753] Fixed test --- util/src/journaldb/earlymergedb.rs | 2 +- util/src/journaldb/overlayrecentdb.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index 64c7fa69d..7f0f50da2 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -575,7 +575,7 @@ mod tests { jdb.remove(&bar); jdb.commit(0, &b"0b".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); - jdb.commit(2, &b"1".sha3(), Some((1, b"1".sha3()))).unwrap(); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index 36e8b68ad..7eb5266b0 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -885,7 +885,7 @@ mod tests { jdb.remove(&bar); jdb.commit(0, &b"0b".sha3(), None).unwrap(); assert!(jdb.can_reconstruct_refs()); - jdb.commit(2, &b"1".sha3(), Some((1, b"1".sha3()))).unwrap(); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); assert!(jdb.exists(&foo)); assert!(jdb.exists(&bar)); From 487ba9b08aacd81224324d3b374433de50a7d5da Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 13 Mar 2016 12:09:30 +0100 Subject: [PATCH 567/753] implemented eth_storageAt rpc method, added more tests for rpc --- ethcore/src/client/client.rs | 4 ++ ethcore/src/client/mod.rs | 3 ++ ethcore/src/client/test_client.rs | 11 +++++ rpc/src/v1/impls/eth.rs | 8 +++- rpc/src/v1/tests/eth.rs | 76 ++++++++++++++++++++++++++++--- 5 files changed, 94 insertions(+), 8 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a860dd752..174142f7a 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -453,6 +453,10 @@ impl BlockChainClient for Client where V: Verifier { self.state().balance(address) } + fn storage_at(&self, address: &Address, position: &H256) -> H256 { + self.state().storage_at(address, position) + } + fn transaction(&self, id: TransactionId) -> Option { match id { TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index af2c6ac14..f07a1f7c3 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -69,6 +69,9 @@ pub trait BlockChainClient : Sync + Send { /// Get address balance. fn balance(&self, address: &Address) -> U256; + /// Get value of the storage at given position. + fn storage_at(&self, address: &Address, position: &H256) -> H256; + /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 997f159d2..0dd4359ce 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -42,6 +42,8 @@ pub struct TestBlockChainClient { pub difficulty: RwLock, /// Balances. pub balances: RwLock>, + /// Storage. + pub storage: RwLock>, } #[derive(Clone)] @@ -74,6 +76,7 @@ impl TestBlockChainClient { last_hash: RwLock::new(H256::new()), difficulty: RwLock::new(From::from(0)), balances: RwLock::new(HashMap::new()), + storage: RwLock::new(HashMap::new()), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); @@ -84,6 +87,10 @@ impl TestBlockChainClient { self.balances.write().unwrap().insert(address, balance); } + pub fn set_storage(&mut self, address: Address, position: H256, value: H256) { + self.storage.write().unwrap().insert((address, position), value); + } + /// Add blocks to test client. pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { let len = self.numbers.read().unwrap().len(); @@ -182,6 +189,10 @@ impl BlockChainClient for TestBlockChainClient { self.balances.read().unwrap().get(address).cloned().unwrap_or_else(U256::zero) } + fn storage_at(&self, address: &Address, position: &H256) -> H256 { + self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new) + } + fn transaction(&self, _id: TransactionId) -> Option { unimplemented!(); } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index f5159f55f..a5736b76b 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -101,7 +101,7 @@ impl EthClient where C: BlockChainClient, S: SyncProvider, A: impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncProvider + 'static, A: AccountProvider + 'static { fn protocol_version(&self, params: Params) -> Result { match params { - Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)), + Params::None => Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())), _ => Err(Error::invalid_params()) } } @@ -175,6 +175,12 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: .and_then(|(address, _block_number)| to_value(&take_weak!(self.client).balance(&address))) } + fn storage_at(&self, params: Params) -> Result { + from_params::<(Address, U256, BlockNumber)>(params) + .and_then(|(address, position, _block_number)| + to_value(&U256::from(take_weak!(self.client).storage_at(&address, &H256::from(position))))) + } + fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 8c61c2ed9..47dc1dd89 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use std::sync::Arc; use jsonrpc_core::IoHandler; -use util::hash::Address; +use util::hash::{Address, H256}; use util::numbers::U256; use ethcore::client::{TestBlockChainClient, EachBlockWith}; use v1::{Eth, EthClient}; @@ -27,6 +27,7 @@ fn blockchain_client() -> Arc { let mut client = TestBlockChainClient::new(); client.add_blocks(10, EachBlockWith::Nothing); client.set_balance(Address::from(1), U256::from(5)); + client.set_storage(Address::from(1), H256::from(4), H256::from(7)); Arc::new(client) } @@ -45,9 +46,9 @@ fn sync_provider() -> Arc { } struct EthTester { - client: Arc, - sync: Arc, - accounts_provider: Arc, + _client: Arc, + _sync: Arc, + _accounts_provider: Arc, pub io: IoHandler, } @@ -60,14 +61,54 @@ impl Default for EthTester { let io = IoHandler::new(); io.add_delegate(eth); EthTester { - client: client, - sync: sync, - accounts_provider: ap, + _client: client, + _sync: sync, + _accounts_provider: ap, io: io } } } +#[test] +fn rpc_eth_protocol_version() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_protocolVersion", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"65","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +#[ignore] +fn rpc_eth_syncing() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_hashrate() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_author() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_mining() { + unimplemented!() +} + +#[test] +fn rpc_eth_gas_price() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_gasPrice", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0ba43b7400","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + #[test] fn rpc_eth_accounts() { let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#; @@ -76,6 +117,14 @@ fn rpc_eth_accounts() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +fn rpc_eth_block_number() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0a","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + #[test] fn rpc_eth_balance() { let request = r#"{ @@ -88,3 +137,16 @@ fn rpc_eth_balance() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } + +#[test] +fn rpc_eth_storage_at() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getStorageAt", + "params": ["0x0000000000000000000000000000000000000001", "0x4", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x07","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} From 450ae4147fa9c6cebf7f10eba70960aa9e610ff2 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 13 Mar 2016 13:03:02 +0100 Subject: [PATCH 568/753] memory and expiration mngmt --- util/src/keys/store.rs | 57 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 610dda9f5..3477130e9 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -135,6 +135,19 @@ impl AccountService { secret_store: secret_store } } + + #[cfg(test)] + fn new_test(temp: &::devtools::RandomTempPath) -> Self { + let secret_store = RwLock::new(SecretStore::new_test(temp)); + AccountService { + secret_store: secret_store + } + } + + /// Ticks the account service + pub fn tick(&self) { + self.secret_store.write().unwrap().collect_garbage(); + } } impl Default for SecretStore { @@ -256,6 +269,17 @@ impl SecretStore { let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); Ok(unlock.secret as crypto::Secret) } + + /// Makes account unlocks expire and removes unused key files from memory + pub fn collect_garbage(&mut self) { + self.directory.collect_garbage(); + let utc = UTC::now(); + let expired_addresses = self.unlocks.read().unwrap().iter() + .filter(|&(_, unlock)| unlock.expires < utc) + .map(|(address, _)| address.clone()).collect::>(); + + for expired in expired_addresses { self.unlocks.write().unwrap().remove(&expired); } + } } fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) { @@ -362,14 +386,12 @@ impl EncryptedHashMap for SecretStore { } -#[cfg(test)] +#[cfg(all(test, feature="heavy-tests"))] mod vector_tests { use super::{derive_mac,derive_key_iterations}; use common::*; - #[test] - #[cfg(feature="heavy-tests")] fn mac_vector() { let password = "testpassword"; let salt = H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(); @@ -395,6 +417,7 @@ mod tests { use devtools::*; use common::*; use crypto::KeyPair; + use chrono::*; #[test] fn can_insert() { @@ -581,4 +604,32 @@ mod tests { let kp = KeyPair::from_secret(secret).unwrap(); assert_eq!(Address::from(kp.public().sha3()), addr); } + + #[test] + fn can_create_service() { + let temp = RandomTempPath::create_dir(); + let svc = AccountService::new_test(&temp); + assert!(svc.accounts().unwrap().is_empty()); + } + + #[test] + fn accounts_expire() { + use std::collections::hash_map::*; + + let temp = RandomTempPath::create_dir(); + let svc = AccountService::new_test(&temp); + let address = svc.new_account("pass").unwrap(); + svc.unlock_account(&address, "pass").unwrap(); + assert!(svc.account_secret(&address).is_ok()); + { + let ss_rw = svc.secret_store.write().unwrap(); + let mut ua_rw = ss_rw.unlocks.write().unwrap(); + let entry = ua_rw.entry(address); + if let Entry::Occupied(mut occupied) = entry { occupied.get_mut().expires = UTC::now() - Duration::minutes(1); } + } + + svc.tick(); + + assert!(svc.account_secret(&address).is_err()); + } } From c2b3ba533b0b4dbfb64ae308a33f8f7849d3fb52 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 13 Mar 2016 14:37:33 +0100 Subject: [PATCH 569/753] fixed eth_getTransactionCount**, and eth_getUncleCount** rpc methods, added tests for them --- rpc/src/v1/impls/eth.rs | 36 ++++++++++++++-------- rpc/src/v1/tests/eth.rs | 66 ++++++++++++++++++++++++++++++++++++++++ rpc/src/v1/traits/eth.rs | 15 +++++---- 3 files changed, 98 insertions(+), 19 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a5736b76b..6d28ccc75 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -181,30 +181,40 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: to_value(&U256::from(take_weak!(self.client).storage_at(&address, &H256::from(position))))) } + fn transaction_count(&self, params: Params) -> Result { + from_params::<(Address, BlockNumber)>(params) + .and_then(|(address, _block_number)| to_value(&take_weak!(self.client).nonce(&address))) + } + fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { - Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), - None => Ok(Value::Null) - }) + .and_then(|(hash,)| // match + to_value(&take_weak!(self.client).block(BlockId::Hash(hash)) + .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count())))) } fn block_transaction_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { - BlockNumber::Pending => to_value(&take_weak!(self.sync).status().transaction_queue_pending), - _ => match take_weak!(self.client).block(block_number.into()) { - Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), - None => Ok(Value::Null) - } + BlockNumber::Pending => to_value(&U256::from(take_weak!(self.sync).status().transaction_queue_pending)), + _ => to_value(&take_weak!(self.client).block(block_number.into()) + .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count()))) }) } - fn block_uncles_count(&self, params: Params) -> Result { + fn block_uncles_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { - Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), - None => Ok(Value::Null) + .and_then(|(hash,)| + to_value(&take_weak!(self.client).block(BlockId::Hash(hash)) + .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).uncles_count())))) + } + + fn block_uncles_count_by_number(&self, params: Params) -> Result { + from_params::<(BlockNumber,)>(params) + .and_then(|(block_number,)| match block_number { + BlockNumber::Pending => to_value(&U256::from(0)), + _ => to_value(&take_weak!(self.client).block(block_number.into()) + .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).uncles_count()))) }) } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 47dc1dd89..bde84491b 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -150,3 +150,69 @@ fn rpc_eth_storage_at() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } + +#[test] +fn rpc_eth_transaction_count() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": ["0x0000000000000000000000000000000000000001", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_block_transaction_count_by_hash() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByHash", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_transaction_count_by_number() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": ["latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_uncle_count_by_block_hash() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockHash", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_uncle_count_by_block_number() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockNumber", + "params": ["latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 7d33cb63f..738f561b2 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -59,14 +59,17 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns the number of transactions sent from given address at given time (block number). fn transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns the number of transactions in a block given block hash. + /// Returns the number of transactions in a block with given hash. fn block_transaction_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns the number of transactions in a block given block number. + /// Returns the number of transactions in a block with given block number. fn block_transaction_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns the number of uncles in a given block. - fn block_uncles_count(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns the number of uncles in a block with given hash. + fn block_uncles_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns the number of uncles in a block with given block number. + fn block_uncles_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns the code at given address at given time (block number). fn code_at(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -135,8 +138,8 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_getTransactionCount", Eth::transaction_count); delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count_by_hash); delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count_by_number); - delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count); - delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count); + delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash); + delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number); delegate.add_method("eth_code", Eth::code_at); delegate.add_method("eth_sendTransaction", Eth::send_transaction); delegate.add_method("eth_call", Eth::call); From 00820c342a7a04f02886c2f920d29a5c0e419c61 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 13 Mar 2016 14:45:39 +0100 Subject: [PATCH 570/753] fixed eth_getCode and added tests for it --- ethcore/src/client/test_client.rs | 14 ++++++++++++-- rpc/src/v1/impls/eth.rs | 3 ++- rpc/src/v1/tests/eth.rs | 14 ++++++++++++++ rpc/src/v1/traits/eth.rs | 2 +- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 0dd4359ce..d85540858 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -44,6 +44,8 @@ pub struct TestBlockChainClient { pub balances: RwLock>, /// Storage. pub storage: RwLock>, + /// Code. + pub code: RwLock>, } #[derive(Clone)] @@ -77,16 +79,24 @@ impl TestBlockChainClient { difficulty: RwLock::new(From::from(0)), balances: RwLock::new(HashMap::new()), storage: RwLock::new(HashMap::new()), + code: RwLock::new(HashMap::new()), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } + /// Set code at given address. + pub fn set_code(&mut self, address: Address, code: Bytes) { + self.code.write().unwrap().insert(address, code); + } + + /// Set balance at given address. pub fn set_balance(&mut self, address: Address, balance: U256) { self.balances.write().unwrap().insert(address, balance); } + /// Set storage at given address and position. pub fn set_storage(&mut self, address: Address, position: H256, value: H256) { self.storage.write().unwrap().insert((address, position), value); } @@ -181,8 +191,8 @@ impl BlockChainClient for TestBlockChainClient { U256::zero() } - fn code(&self, _address: &Address) -> Option { - unimplemented!(); + fn code(&self, address: &Address) -> Option { + self.code.read().unwrap().get(address).cloned() } fn balance(&self, address: &Address) -> U256 { diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 6d28ccc75..2c7e16af5 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -221,7 +221,8 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: // TODO: do not ignore block number param fn code_at(&self, params: Params) -> Result { from_params::<(Address, BlockNumber)>(params) - .and_then(|(address, _block_number)| to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new))) + .and_then(|(address, _block_number)| + to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new))) } fn block_by_hash(&self, params: Params) -> Result { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index bde84491b..a636ba278 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -28,6 +28,7 @@ fn blockchain_client() -> Arc { client.add_blocks(10, EachBlockWith::Nothing); client.set_balance(Address::from(1), U256::from(5)); client.set_storage(Address::from(1), H256::from(4), H256::from(7)); + client.set_code(Address::from(1), vec![0xff, 0x21]); Arc::new(client) } @@ -216,3 +217,16 @@ fn rpc_eth_uncle_count_by_block_number() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +fn rpc_eth_code() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getCode", + "params": ["0x0000000000000000000000000000000000000001", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0xff21","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 738f561b2..0b09012ab 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -140,7 +140,7 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count_by_number); delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash); delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number); - delegate.add_method("eth_code", Eth::code_at); + delegate.add_method("eth_getCode", Eth::code_at); delegate.add_method("eth_sendTransaction", Eth::send_transaction); delegate.add_method("eth_call", Eth::call); delegate.add_method("eth_estimateGas", Eth::estimate_gas); From 89dc6fa9ccc57233dccd23402dbd29eae2a60a8e Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 13 Mar 2016 14:46:45 +0100 Subject: [PATCH 571/753] io handlers --- parity/main.rs | 13 +++++++++++-- util/src/keys/store.rs | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index b16801ad5..7a92e5570 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -445,6 +445,7 @@ impl Configuration { // Secret Store let account_service = Arc::new(AccountService::new()); + service.io().register_handler(account_service).expect("Error registering IO handler"); // Setup rpc if self.args.flag_jsonrpc || self.args.flag_rpc { @@ -468,6 +469,7 @@ impl Configuration { client: service.client(), info: Default::default(), sync: sync.clone(), + accounts: account_service.clone(), }); service.io().register_handler(io_handler).expect("Error registering IO handler"); @@ -559,20 +561,27 @@ impl Informant { const INFO_TIMER: TimerToken = 0; +const ACCOUNT_TICK_TIMER: TimerToken = 10; +const ACCOUNT_TICK_MS: u64 = 60000; + struct ClientIoHandler { client: Arc, sync: Arc, + accounts: Arc, info: Informant, } impl IoHandler for ClientIoHandler { fn initialize(&self, io: &IoContext) { io.register_timer(INFO_TIMER, 5000).expect("Error registering timer"); + io.register_timer(ACCOUNT_TICK_TIMER, ACCOUNT_TICK_MS).expect("Error registering account timer"); + } fn timeout(&self, _io: &IoContext, timer: TimerToken) { - if INFO_TIMER == timer { - self.info.tick(&self.client, &self.sync); + match timer { + INFO_TIMER => { self.info.tick(&self.client, &self.sync); } + ACCOUNT_TICK_TIMER => { self.accounts.tick(); } } } } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 610dda9f5..68121a82b 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -137,6 +137,7 @@ impl AccountService { } } + impl Default for SecretStore { fn default() -> Self { SecretStore::new() From 29c85e16cd57bae94e058883f4ee912787a24754 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 13 Mar 2016 14:57:26 +0100 Subject: [PATCH 572/753] added eth_sign and eth_sendRawTransaction to eth interface --- rpc/src/v1/tests/eth.rs | 33 +++++++++++++++++++++++++++++++++ rpc/src/v1/traits/eth.rs | 8 ++++++++ 2 files changed, 41 insertions(+) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index a636ba278..6e408e9f7 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -230,3 +230,36 @@ fn rpc_eth_code() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +#[ignore] +fn rpc_eth_call() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_send_transaction() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_send_raw_transaction() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_sign() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_estimate_gas() { + unimplemented!() +} + + + + diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 0b09012ab..bcd7e7cfe 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -74,9 +74,15 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns the code at given address at given time (block number). fn code_at(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Signs the data with given address signature. + fn sign(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Sends transaction. fn send_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Sends signed transaction. + fn send_raw_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Call contract. fn call(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -141,7 +147,9 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash); delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number); delegate.add_method("eth_getCode", Eth::code_at); + delegate.add_method("eth_sign", Eth::sign); delegate.add_method("eth_sendTransaction", Eth::send_transaction); + delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction); delegate.add_method("eth_call", Eth::call); delegate.add_method("eth_estimateGas", Eth::estimate_gas); delegate.add_method("eth_getBlockByHash", Eth::block_by_hash); From 4a58e142bd2062ccc7491e2f04b4e907224f3283 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 15:02:08 +0100 Subject: [PATCH 573/753] Remove duplicate ciippys. --- Cargo.toml | 3 +-- rpc/Cargo.toml | 3 +-- sync/Cargo.toml | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3dcad0f8..351041119 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,15 +19,14 @@ ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } fdlimit = { path = "util/fdlimit" } daemonize = "0.2" number_prefix = "0.2" -clippy = { version = "0.0.50", optional = true } rpassword = "0.1" +clippy = { version = "0.0.50", optional = true } ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } -clippy = { version = "0.0.49", optional = true } [features] default = ["rpc"] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 70cc2ec42..fa89041d8 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,12 +18,11 @@ ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } -clippy = { version = "0.0.50", optional = true } ethminer = { path = "../miner" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.49", optional = true } +clippy = { version = "0.0.50", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 2765b0680..8cd59333d 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -17,7 +17,6 @@ env_logger = "0.3" time = "0.1.34" rand = "0.3.13" heapsize = "0.3" -clippy = { version = "0.0.49", optional = true } [features] default = [] From 6ee13b0000dc9f4cd8bfc3505b95f3d522471f2a Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 13 Mar 2016 15:02:46 +0100 Subject: [PATCH 574/753] implemented eth_getCompilers --- rpc/src/v1/impls/eth.rs | 7 +++++++ rpc/src/v1/tests/eth.rs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2c7e16af5..8ff1f30d0 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -250,6 +250,13 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: .and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value()))) } + fn compilers(&self, params: Params) -> Result { + match params { + Params::None => to_value(&vec![] as &Vec), + _ => Err(Error::invalid_params()) + } + } + fn logs(&self, params: Params) -> Result { from_params::<(Filter,)>(params) .and_then(|(filter,)| { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 6e408e9f7..3d4fb0451 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -260,6 +260,13 @@ fn rpc_eth_estimate_gas() { unimplemented!() } +#[test] +fn rpc_eth_compilers() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":[],"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} From a4f03100e9633d411d65a17fa568330c51be063f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 13 Mar 2016 15:11:16 +0100 Subject: [PATCH 575/753] registering timer --- parity/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 7a92e5570..1bfd2ced1 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -445,7 +445,6 @@ impl Configuration { // Secret Store let account_service = Arc::new(AccountService::new()); - service.io().register_handler(account_service).expect("Error registering IO handler"); // Setup rpc if self.args.flag_jsonrpc || self.args.flag_rpc { @@ -581,7 +580,8 @@ impl IoHandler for ClientIoHandler { fn timeout(&self, _io: &IoContext, timer: TimerToken) { match timer { INFO_TIMER => { self.info.tick(&self.client, &self.sync); } - ACCOUNT_TICK_TIMER => { self.accounts.tick(); } + ACCOUNT_TICK_TIMER => { self.accounts.tick(); }, + _ => {} } } } From 08b9cc2c41d3ae7a761984acc5f2a2956b18a1c1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 15:29:55 +0100 Subject: [PATCH 576/753] Merge changes from #674 into branch. --- Cargo.lock | 10 ++++++ ethcore/src/client/client.rs | 67 ++++++++++++++++++++++++++---------- ethcore/src/service.rs | 8 +++-- miner/src/lib.rs | 2 +- miner/src/miner.rs | 15 +++++--- parity/main.rs | 21 ++++++----- sync/src/chain.rs | 8 ++--- sync/src/lib.rs | 4 +-- sync/src/tests/helpers.rs | 2 +- 9 files changed, 93 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8552f299f..d68c5c121 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,6 +93,16 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clippy" +version = "0.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clippy" version = "0.0.50" diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 520b069e1..8c3d73ebb 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -35,7 +35,7 @@ use extras::TransactionAddress; use filter::Filter; use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; -use blockchain::{BlockChain, BlockProvider, TreeRoute}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; pub use blockchain::CacheSize as BlockChainCacheSize; @@ -222,12 +222,39 @@ impl Client where V: Verifier { Ok(closed_block) } + fn calculate_enacted_retracted(&self, import_results: Vec) -> (Vec, Vec) { + fn map_to_vec(map: Vec<(H256, bool)>) -> Vec { + map.into_iter().map(|(k, _v)| k).collect() + } + + // In ImportRoute we get all the blocks that have been enacted and retracted by single insert. + // Because we are doing multiple inserts some of the blocks that were enacted in import `k` + // could be retracted in import `k+1`. This is why to understand if after all inserts + // the block is enacted or retracted we iterate over all routes and at the end final state + // will be in the hashmap + let map = import_results.into_iter().fold(HashMap::new(), |mut map, route| { + for hash in route.enacted { + map.insert(hash, true); + } + for hash in route.retracted { + map.insert(hash, false); + } + map + }); + + // Split to enacted retracted (using hashmap value) + let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v); + // And convert tuples to keys + (map_to_vec(enacted), map_to_vec(retracted)) + } + /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self, io: &IoChannel) -> usize { let max_blocks_to_import = 128; - let mut good_blocks = Vec::with_capacity(max_blocks_to_import); - let mut bad_blocks = HashSet::new(); + let mut imported_blocks = Vec::with_capacity(max_blocks_to_import); + let mut invalid_blocks = HashSet::new(); + let mut import_results = Vec::with_capacity(max_blocks_to_import); let _import_lock = self.import_lock.lock(); let blocks = self.block_queue.drain(max_blocks_to_import); @@ -237,16 +264,16 @@ impl Client where V: Verifier { for block in blocks { let header = &block.header; - if bad_blocks.contains(&header.parent_hash) { - bad_blocks.insert(header.hash()); + if invalid_blocks.contains(&header.parent_hash) { + invalid_blocks.insert(header.hash()); continue; } let closed_block = self.check_and_close_block(&block); if let Err(_) = closed_block { - bad_blocks.insert(header.hash()); + invalid_blocks.insert(header.hash()); break; } - good_blocks.push(header.hash()); + imported_blocks.push(header.hash()); // Are we committing an era? let ancient = if header.number() >= HISTORY { @@ -265,31 +292,33 @@ impl Client where V: Verifier { // And update the chain after commit to prevent race conditions // (when something is in chain but you are not able to fetch details) - self.chain.insert_block(&block.bytes, receipts); + let route = self.chain.insert_block(&block.bytes, receipts); + import_results.push(route); self.report.write().unwrap().accrue_block(&block); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); } - let imported = good_blocks.len(); - let bad_blocks = bad_blocks.into_iter().collect::>(); + let imported = imported_blocks.len(); + let invalid_blocks = invalid_blocks.into_iter().collect::>(); { - if !bad_blocks.is_empty() { - self.block_queue.mark_as_bad(&bad_blocks); + if !invalid_blocks.is_empty() { + self.block_queue.mark_as_bad(&invalid_blocks); } - if !good_blocks.is_empty() { - self.block_queue.mark_as_good(&good_blocks); + if !imported_blocks.is_empty() { + self.block_queue.mark_as_good(&imported_blocks); } } { - if !good_blocks.is_empty() && self.block_queue.queue_info().is_empty() { + if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { + let (enacted, retracted) = self.calculate_enacted_retracted(import_results); io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { - good: good_blocks, - bad: bad_blocks, - // TODO [todr] were to take those from? - retracted: vec![], + good: imported_blocks, + invalid: invalid_blocks, + enacted: enacted, + retracted: retracted, })).unwrap(); } } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 27303bea7..bcfe7724f 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -28,11 +28,13 @@ pub enum SyncMessage { /// New block has been imported into the blockchain NewChainBlocks { /// Hashes of blocks imported to blockchain - good: Vec, - /// Hashes of blocks not imported to blockchain - bad: Vec, + imported: Vec, + /// Hashes of blocks not imported to blockchain (because were invalid) + invalid: Vec, /// Hashes of blocks that were removed from canonical chain retracted: Vec, + /// Hashes of blocks that are now included in cannonical chain + enacted: Vec, }, /// Best Block Hash in chain has been changed NewChainHead, diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 9c2ad9ba5..a431bd44e 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -89,7 +89,7 @@ pub trait MinerService : Send + Sync { fn clear_and_reset(&self, chain: &BlockChainClient); /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], retracted: &[H256]); + fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); /// New chain head event. Restart mining operation. fn prepare_sealing(&self, chain: &BlockChainClient); diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 00efb83d3..a07da7569 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -150,7 +150,7 @@ impl MinerService for Miner { } } - fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]) { + fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], _retracted: &[H256]) { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockId::Hash(*hash)) @@ -161,15 +161,20 @@ impl MinerService for Miner { } { - let good = good.par_iter().map(|h| fetch_transactions(chain, h)); - let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); + let in_chain = vec![imported, enacted, invalid]; + let in_chain = in_chain + .par_iter() + .flat_map(|h| h.par_iter().map(|h| fetch_transactions(chain, h))); + .map(|h| fetch_transactions(chain, h)); + let out_of_chain = retracted + .par_iter() - good.for_each(|txs| { + in_chain.for_each(|txs| { let mut transaction_queue = self.transaction_queue.lock().unwrap(); let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); }); - bad.for_each(|txs| { + out_of_chain.for_each(|txs| { // populate sender for tx in &txs { let _sender = tx.sender(); diff --git a/parity/main.rs b/parity/main.rs index eb1937757..56a7d48de 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -114,7 +114,7 @@ API and Console Options: --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). Sealing/Mining Options: - --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 20000000000]. + --gas-price WEI Minimum amount of Wei to be paid for a transaction to be accepted for mining [default: 20000000000]. --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. @@ -138,11 +138,12 @@ Geth-Compatibility Options --maxpeers COUNT Equivalent to --peers COUNT. --nodekey KEY Equivalent to --node-key KEY. --nodiscover Equivalent to --no-discovery. + --gasprice WEI Equivalent to --gas-price WEI. --etherbase ADDRESS Equivalent to --author ADDRESS. --extradata STRING Equivalent to --extra-data STRING. Miscellaneous Options: - -l --logging LOGGING Specify the logging level. + -l --logging LOGGING Specify the logging level. Must conform to the same format as RUST_LOG. -v --version Show information about version. -h --help Show this screen. "#; @@ -175,18 +176,19 @@ struct Args { flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, + flag_author: String, + flag_gas_price: String, + flag_extra_data: Option, flag_logging: Option, flag_version: bool, // geth-compatibility... flag_nodekey: Option, flag_nodiscover: bool, flag_maxpeers: Option, - flag_gasprice: String, - flag_author: String, - flag_extra_data: Option, flag_datadir: Option, flag_extradata: Option, flag_etherbase: Option, + flag_gasprice: Option, flag_rpc: bool, flag_rpcaddr: Option, flag_rpcport: Option, @@ -301,9 +303,10 @@ impl Configuration { }) } - fn gasprice(&self) -> U256 { - U256::from_dec_str(self.args.flag_gasprice.as_str()).unwrap_or_else(|_| { - die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", self.args.flag_gasprice) + fn gas_price(&self) -> U256 { + let d = self.args.flag_gasprice.as_ref().unwrap_or(&self.args.flag_gas_price); + U256::from_dec_str(d).unwrap_or_else(|_| { + die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", d) }) } @@ -483,7 +486,7 @@ impl Configuration { let miner = Miner::new(); miner.set_author(self.author()); miner.set_extra_data(self.extra_data()); - miner.set_minimal_gas_price(self.gasprice()); + miner.set_minimal_gas_price(self.gas_price()); // Sync let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index e622f0b86..d06a34764 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1263,9 +1263,9 @@ impl ChainSync { } /// called when block is imported to chain, updates transactions queue and propagates the blocks - pub fn chain_new_blocks(&mut self, io: &mut SyncIo, good: &[H256], bad: &[H256], retracted: &[H256]) { + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { // Notify miner - self.miner.chain_new_blocks(io.chain(), good, bad, retracted); + self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); // Propagate latests blocks self.propagate_latest_blocks(io); // TODO [todr] propagate transactions? @@ -1616,10 +1616,10 @@ mod tests { let mut io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&mut io, &[], &good_blocks, &[]); + sync.chain_new_blocks(&mut io, &[], &good_blocks, &[], &[]); assert_eq!(sync.miner.status().transaction_queue_future, 0); assert_eq!(sync.miner.status().transaction_queue_pending, 1); - sync.chain_new_blocks(&mut io, &good_blocks, &retracted_blocks, &[]); + sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); // then let status = sync.miner.status(); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 0c7abd1d0..c47b74b66 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -167,9 +167,9 @@ impl NetworkProtocolHandler for EthSync { #[allow(single_match)] fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { - SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted } => { + SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&mut sync_io, good, bad, retracted); + self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted); }, SyncMessage::NewChainHead => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 00df35e77..b3e62ccc6 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -168,6 +168,6 @@ impl TestNet { pub fn trigger_chain_new_blocks(&mut self, peer_id: usize) { let mut peer = self.peer_mut(peer_id); - peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[]); + peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[], &[]); } } From 76696e3b49a2a8e84caa11a1d27c2f9ad5e78cb8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 15:36:03 +0100 Subject: [PATCH 577/753] Minor build fixes. --- ethcore/src/client/client.rs | 2 +- ethcore/src/client/test_client.rs | 2 ++ miner/src/miner.rs | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8c3d73ebb..d748cc4ee 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -315,7 +315,7 @@ impl Client where V: Verifier { if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { let (enacted, retracted) = self.calculate_enacted_retracted(import_results); io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { - good: imported_blocks, + imported: imported_blocks, invalid: invalid_blocks, enacted: enacted, retracted: retracted, diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index d801c08e0..a97228b09 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -83,10 +83,12 @@ impl TestBlockChainClient { client } + /// Set the balance of account `address` to `balance`. pub fn set_balance(&mut self, address: Address, balance: U256) { self.balances.write().unwrap().insert(address, balance); } + /// Set storage `position` to `value` for account `address`. pub fn set_storage(&mut self, address: Address, position: H256, value: H256) { self.storage.write().unwrap().insert((address, position), value); } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index a07da7569..ad403150d 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -150,7 +150,7 @@ impl MinerService for Miner { } } - fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], _retracted: &[H256]) { + fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockId::Hash(*hash)) @@ -165,9 +165,9 @@ impl MinerService for Miner { let in_chain = in_chain .par_iter() .flat_map(|h| h.par_iter().map(|h| fetch_transactions(chain, h))); - .map(|h| fetch_transactions(chain, h)); let out_of_chain = retracted .par_iter() + .map(|h| fetch_transactions(chain, h)); in_chain.for_each(|txs| { let mut transaction_queue = self.transaction_queue.lock().unwrap(); From 809c239ff80dd31467fcdef8f5be5da42fe95106 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 13 Mar 2016 15:59:25 +0100 Subject: [PATCH 578/753] fix rev --- ethcore/src/client/client.rs | 6 +----- sync/src/chain.rs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 95ee90f7d..81e1ef287 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -471,11 +471,7 @@ impl BlockChainClient for Client where V: Verifier { } fn block_receipts(&self, hash: &H256) -> Option { - self.chain.block_receipts(hash).and_then(|receipts| { - let mut rlp = RlpStream::new(); - rlp.append(&receipts); - Some(rlp.out()) - }) + self.chain.block_receipts(hash).map(|receipts| rlp::encode(&receipts).to_vec()) } fn import_block(&self, bytes: Bytes) -> ImportResult { diff --git a/sync/src/chain.rs b/sync/src/chain.rs index ae4744902..bc3041d02 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -66,7 +66,7 @@ const MAX_BODIES_TO_SEND: usize = 256; const MAX_HEADERS_TO_SEND: usize = 512; const MAX_NODE_DATA_TO_SEND: usize = 1024; const MAX_RECEIPTS_TO_SEND: usize = 1024; -const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 16; +const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256; const MAX_HEADERS_TO_REQUEST: usize = 512; const MAX_BODIES_TO_REQUEST: usize = 256; const MIN_PEERS_PROPAGATION: usize = 4; From 6cedb263aa5857ec480ab9ea86061fe90dac8c7d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 17:01:50 +0100 Subject: [PATCH 579/753] Add missing file. --- rpc/src/v1/tests/helpers/miner_service.rs | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 rpc/src/v1/tests/helpers/miner_service.rs diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs new file mode 100644 index 000000000..0cddf2a1e --- /dev/null +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -0,0 +1,53 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::{Address, H256, U256, Bytes}; +use util::standard::*; +use ethcore::error::Error; +use ethcore::client::BlockChainClient; +use ethcore::block::ClosedBlock; +use ethcore::transaction::SignedTransaction; +use ethminer::{MinerService, MinerStatus}; + +pub struct TestMinerService; + +impl MinerService for TestMinerService { + + /// Returns miner's status. + fn status(&self) -> MinerStatus { unimplemented!(); } + + /// Imports transactions to transaction queue. + fn import_transactions(&self, _transactions: Vec, _fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256 { unimplemented!(); } + + /// Returns hashes of transactions currently in pending + fn pending_transactions_hashes(&self) -> Vec { unimplemented!(); } + + /// Removes all transactions from the queue and restart mining operation. + fn clear_and_reset(&self, _chain: &BlockChainClient) { unimplemented!(); } + + /// Called when blocks are imported to chain, updates transactions queue. + fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); } + + /// New chain head event. Restart mining operation. + fn prepare_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } + + /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. + fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex> { unimplemented!(); } + + /// Submit `seal` as a valid solution for the header of `pow_hash`. + /// Will check the seal, but not actually insert the block into the chain. + fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { unimplemented!(); } +} \ No newline at end of file From 9e912c7c0dd19054a9fa04cb8c488530667f8c06 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 18:07:10 +0100 Subject: [PATCH 580/753] Add new file. --- util/src/journaldb/refcounteddb.rs | 264 +++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 util/src/journaldb/refcounteddb.rs diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs new file mode 100644 index 000000000..32471b36c --- /dev/null +++ b/util/src/journaldb/refcounteddb.rs @@ -0,0 +1,264 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Disk-backed, ref-counted JournalDB implementation. + +use common::*; +use rlp::*; +use hashdb::*; +use overlaydb::*; +use super::traits::JournalDB; +use kvdb::{Database, DBTransaction, DatabaseConfig}; +#[cfg(test)] +use std::env; + +/// Implementation of the HashDB trait for a disk-backed database with a memory overlay +/// and latent-removal semantics. +/// +/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to +/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect +/// immediately. Rather some age (based on a linear but arbitrary metric) must pass before +/// the removals actually take effect. +pub struct RefCountedDB { + forward: OverlayDB, + backing: Arc, + inserts: Vec, + removes: Vec, +} + +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const DB_VERSION : u32 = 512; + +impl RefCountedDB { + /// Create a new instance given a `backing` database. + pub fn new(path: &str) -> RefCountedDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(&opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + if !backing.is_empty() { + match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { + Ok(Some(DB_VERSION)) => {}, + v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) + } + } else { + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + } + + let backing = Arc::new(backing); + RefCountedDB { + forward: OverlayDB::new_with_arc(backing.clone()), + backing: backing, + inserts: vec![], + removes: vec![], + } + } + + /// Create a new instance with an anonymous temporary database. + #[cfg(test)] + fn new_temp() -> RefCountedDB { + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + Self::new(dir.to_str().unwrap()) + } +} + +impl HashDB for RefCountedDB { + fn keys(&self) -> HashMap { self.forward.keys() } + fn lookup(&self, key: &H256) -> Option<&[u8]> { self.forward.lookup(key) } + fn exists(&self, key: &H256) -> bool { self.forward.exists(key) } + fn insert(&mut self, value: &[u8]) -> H256 { let r = self.forward.insert(value); self.inserts.push(r.clone()); r } + fn emplace(&mut self, key: H256, value: Bytes) { self.inserts.push(key.clone()); self.forward.emplace(key, value); } + fn kill(&mut self, key: &H256) { self.removes.push(key.clone()); } +} + +impl JournalDB for RefCountedDB { + fn spawn(&self) -> Box { + Box::new(RefCountedDB { + forward: self.forward.clone(), + backing: self.backing.clone(), + inserts: self.inserts.clone(), + removes: self.removes.clone(), + }) + } + + fn mem_used(&self) -> usize { + self.inserts.heap_size_of_children() + self.removes.heap_size_of_children() + } + + fn is_empty(&self) -> bool { + self.backing.get(&VERSION_KEY).expect("Low level database error").is_none() + } + + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + // journal format: + // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] + // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] + // [era, n] => [ ... ] + + // TODO: store last_era, reclaim_period. + + // when we make a new commit, we journal the inserts and removes. + // for each end_era that we journaled that we are no passing by, + // we remove all of its removes assuming it is canonical and all + // of its inserts otherwise. + + // record new commit's details. + let batch = DBTransaction::new(); + { + let mut index = 0usize; + let mut last; + + while try!(self.backing.get({ + let mut r = RlpStream::new_list(2); + r.append(&now); + r.append(&index); + last = r.drain(); + &last + })).is_some() { + index += 1; + } + + let mut r = RlpStream::new_list(3); + r.append(id); + r.append(&self.inserts); + r.append(&self.removes); + try!(self.backing.put(&last, r.as_raw())); + self.inserts.clear(); + self.removes.clear(); + } + + // apply old commits' details + if let Some((end_era, canon_id)) = end { + let mut index = 0usize; + let mut last; + while let Some(rlp_data) = try!(self.backing.get({ + let mut r = RlpStream::new_list(2); + r.append(&end_era); + r.append(&index); + last = r.drain(); + &last + })) { + let rlp = Rlp::new(&rlp_data); + let to_remove: Vec = rlp.val_at(if canon_id == rlp.val_at(0) {2} else {1}); + for i in &to_remove { + self.forward.remove(i); + } + try!(self.backing.delete(&last)); + trace!("RefCountedDB: delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, to_remove.len()); + index += 1; + } + } + + let r = try!(self.forward.commit_to_batch(&batch)); + try!(self.backing.write(batch)); + Ok(r) + } +} + +#[cfg(test)] +mod tests { + use common::*; + use super::*; + use super::super::traits::JournalDB; + use hashdb::*; + + #[test] + fn long_history() { + // history is 3 + let mut jdb = RefCountedDB::new_temp(); + let h = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.remove(&h); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(!jdb.exists(&h)); + } + + #[test] + fn complex() { + // history is 1 + let mut jdb = RefCountedDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + jdb.remove(&bar); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + let foo = jdb.insert(b"foo"); + jdb.remove(&baz); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(!jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + } + + #[test] + fn fork() { + // history is 1 + let mut jdb = RefCountedDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } +} From ac655af09138347d2d716ef42b2dfad038cd7549 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 18:07:36 +0100 Subject: [PATCH 581/753] Update overlaydb --- util/src/overlaydb.rs | 70 ++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index 7c9b6b04b..8166dd318 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -26,7 +26,7 @@ use std::ops::*; use std::sync::*; use std::env; use std::collections::HashMap; -use kvdb::{Database}; +use kvdb::{Database, DBTransaction}; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay. /// @@ -36,7 +36,7 @@ use kvdb::{Database}; /// /// `lookup()` and `contains()` maintain normal behaviour - all `insert()` and `remove()` /// queries have an immediate effect in terms of these functions. -//#[derive(Clone)] +#[derive(Clone)] pub struct OverlayDB { overlay: MemoryDB, backing: Arc, @@ -58,6 +58,36 @@ impl OverlayDB { Self::new(Database::open_default(dir.to_str().unwrap()).unwrap()) } + /// Commit all operations to given batch. + pub fn commit_to_batch(&mut self, batch: &DBTransaction) -> Result { + let mut ret = 0u32; + let mut deletes = 0usize; + for i in self.overlay.drain().into_iter() { + let (key, (value, rc)) = i; + if rc != 0 { + match self.payload(&key) { + Some(x) => { + let (back_value, back_rc) = x; + let total_rc: i32 = back_rc as i32 + rc; + if total_rc < 0 { + return Err(From::from(BaseDataError::NegativelyReferencedHash)); + } + deletes += if self.put_payload(batch, &key, (back_value, total_rc as u32)) {1} else {0}; + } + None => { + if rc < 0 { + return Err(From::from(BaseDataError::NegativelyReferencedHash)); + } + self.put_payload(batch, &key, (value, rc as u32)); + } + }; + ret += 1; + } + } + trace!("OverlayDB::commit() deleted {} nodes", deletes); + Ok(ret) + } + /// Commit all memory operations to the backing database. /// /// Returns either an error or the number of items changed in the backing database. @@ -86,32 +116,10 @@ impl OverlayDB { /// } /// ``` pub fn commit(&mut self) -> Result { - let mut ret = 0u32; - let mut deletes = 0usize; - for i in self.overlay.drain().into_iter() { - let (key, (value, rc)) = i; - if rc != 0 { - match self.payload(&key) { - Some(x) => { - let (back_value, back_rc) = x; - let total_rc: i32 = back_rc as i32 + rc; - if total_rc < 0 { - return Err(From::from(BaseDataError::NegativelyReferencedHash)); - } - deletes += if self.put_payload(&key, (back_value, total_rc as u32)) {1} else {0}; - } - None => { - if rc < 0 { - return Err(From::from(BaseDataError::NegativelyReferencedHash)); - } - self.put_payload(&key, (value, rc as u32)); - } - }; - ret += 1; - } - } - trace!("OverlayDB::commit() deleted {} nodes", deletes); - Ok(ret) + let batch = DBTransaction::new(); + let r = try!(self.commit_to_batch(&batch)); + try!(self.backing.write(batch)); + Ok(r) } /// Revert all operations on this object (i.e. `insert()`s and `kill()`s) since the @@ -148,15 +156,15 @@ impl OverlayDB { } /// Put the refs and value of the given key, possibly deleting it from the db. - fn put_payload(&self, key: &H256, payload: (Bytes, u32)) -> bool { + fn put_payload(&self, batch: &DBTransaction, key: &H256, payload: (Bytes, u32)) -> bool { if payload.1 > 0 { let mut s = RlpStream::new_list(2); s.append(&payload.1); s.append(&payload.0); - self.backing.put(&key.bytes(), s.as_raw()).expect("Low-level database error. Some issue with your hard disk?"); + batch.put(&key.bytes(), s.as_raw()).expect("Low-level database error. Some issue with your hard disk?"); false } else { - self.backing.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + batch.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?"); true } } From 5107fc5897a92746a38a6f35af0b526827a3fbd2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 18:09:44 +0100 Subject: [PATCH 582/753] Update options. --- parity/main.rs | 4 ++-- util/src/journaldb/mod.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index b16801ad5..2bfa75e8a 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -81,7 +81,7 @@ Protocol Options: --testnet Equivalent to --chain testnet (geth-compatible). --networkid INDEX Override the network identifier from the chain we are on. --pruning METHOD Configure pruning of the state/storage trie. METHOD may be one of: archive, - light (experimental), fast (experimental) [default: archive]. + basic (experimental), light (experimental), fast (experimental) [default: archive]. -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] @@ -429,7 +429,7 @@ impl Configuration { "" | "archive" => journaldb::Algorithm::Archive, "pruned" => journaldb::Algorithm::EarlyMerge, "fast" => journaldb::Algorithm::OverlayRecent, -// "slow" => journaldb::Algorithm::RefCounted, // TODO: @gavofyork uncomment this once ref-count algo is merged. + "slow" => journaldb::Algorithm::RefCounted, _ => { die!("Invalid pruning method given."); } }; client_config.name = self.args.flag_identity.clone(); diff --git a/util/src/journaldb/mod.rs b/util/src/journaldb/mod.rs index cf5278368..e73c12969 100644 --- a/util/src/journaldb/mod.rs +++ b/util/src/journaldb/mod.rs @@ -23,6 +23,7 @@ pub mod traits; mod archivedb; mod earlymergedb; mod overlayrecentdb; +mod refcounteddb; /// Export the JournalDB trait. pub use self::traits::JournalDB; @@ -75,6 +76,6 @@ pub fn new(path: &str, algorithm: Algorithm) -> Box { Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)), Algorithm::EarlyMerge => Box::new(earlymergedb::EarlyMergeDB::new(path)), Algorithm::OverlayRecent => Box::new(overlayrecentdb::OverlayRecentDB::new(path)), - _ => unimplemented!(), + Algorithm::RefCounted => Box::new(refcounteddb::RefCountedDB::new(path)), } } From 706c56f56a8758413d722fd97338cea37bf1a059 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 18:19:52 +0100 Subject: [PATCH 583/753] Usage of LATEST_ERA fixes for archive and ref-counted DBs. --- util/src/journaldb/archivedb.rs | 6 +++++- util/src/journaldb/refcounteddb.rs | 13 ++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 2e4e966c1..19570b281 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -35,6 +35,7 @@ use std::env; pub struct ArchiveDB { overlay: MemoryDB, backing: Arc, + latest_era: Option, } // all keys must be at least 12 bytes @@ -60,9 +61,11 @@ impl ArchiveDB { backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); } + let latest_era = backing.get(&LATEST_ERA_KEY).expect("Low-level database error.").map(|val| decode::(&val)); ArchiveDB { overlay: MemoryDB::new(), backing: Arc::new(backing), + latest_era: latest_era, } } @@ -129,6 +132,7 @@ impl JournalDB for ArchiveDB { Box::new(ArchiveDB { overlay: MemoryDB::new(), backing: self.backing.clone(), + latest_era: None, }) } @@ -137,7 +141,7 @@ impl JournalDB for ArchiveDB { } fn is_empty(&self) -> bool { - self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + self.latest_era.is_none() } fn commit(&mut self, _: u64, _: &H256, _: Option<(u64, H256)>) -> Result { diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 32471b36c..09362676b 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -35,10 +35,12 @@ use std::env; pub struct RefCountedDB { forward: OverlayDB, backing: Arc, + latest_era: Option, inserts: Vec, removes: Vec, } +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; const DB_VERSION : u32 = 512; @@ -61,11 +63,14 @@ impl RefCountedDB { } let backing = Arc::new(backing); + let latest_era = backing.get(&LATEST_ERA_KEY).expect("Low-level database error.").map(|val| decode::(&val)); + RefCountedDB { forward: OverlayDB::new_with_arc(backing.clone()), backing: backing, inserts: vec![], removes: vec![], + latest_era: latest_era, } } @@ -92,6 +97,7 @@ impl JournalDB for RefCountedDB { Box::new(RefCountedDB { forward: self.forward.clone(), backing: self.backing.clone(), + latest_era: self.latest_era, inserts: self.inserts.clone(), removes: self.removes.clone(), }) @@ -102,7 +108,7 @@ impl JournalDB for RefCountedDB { } fn is_empty(&self) -> bool { - self.backing.get(&VERSION_KEY).expect("Low level database error").is_none() + self.latest_era.is_none() } fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { @@ -141,6 +147,11 @@ impl JournalDB for RefCountedDB { try!(self.backing.put(&last, r.as_raw())); self.inserts.clear(); self.removes.clear(); + + if self.latest_era.map_or(true, |e| now > e) { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + self.latest_era = Some(now); + } } // apply old commits' details From 81291622eb9da914cfa1e6ba123245edfa48cd56 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 19:22:42 +0100 Subject: [PATCH 584/753] Avoid batches for now. --- parity/main.rs | 4 +-- util/src/journaldb/archivedb.rs | 8 +++-- util/src/journaldb/refcounteddb.rs | 2 +- util/src/overlaydb.rs | 50 +++++++++++++++++++++++++----- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 2bfa75e8a..002655951 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -427,9 +427,9 @@ impl Configuration { } client_config.pruning = match self.args.flag_pruning.as_str() { "" | "archive" => journaldb::Algorithm::Archive, - "pruned" => journaldb::Algorithm::EarlyMerge, + "light" => journaldb::Algorithm::EarlyMerge, "fast" => journaldb::Algorithm::OverlayRecent, - "slow" => journaldb::Algorithm::RefCounted, + "basic" => journaldb::Algorithm::RefCounted, _ => { die!("Invalid pruning method given."); } }; client_config.name = self.args.flag_identity.clone(); diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 19570b281..83a80b7c2 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -132,7 +132,7 @@ impl JournalDB for ArchiveDB { Box::new(ArchiveDB { overlay: MemoryDB::new(), backing: self.backing.clone(), - latest_era: None, + latest_era: self.latest_era, }) } @@ -144,7 +144,7 @@ impl JournalDB for ArchiveDB { self.latest_era.is_none() } - fn commit(&mut self, _: u64, _: &H256, _: Option<(u64, H256)>) -> Result { + fn commit(&mut self, now: u64, _: &H256, _: Option<(u64, H256)>) -> Result { let batch = DBTransaction::new(); let mut inserts = 0usize; let mut deletes = 0usize; @@ -160,6 +160,10 @@ impl JournalDB for ArchiveDB { deletes += 1; } } + if self.latest_era.map_or(true, |e| now > e) { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + self.latest_era = Some(now); + } try!(self.backing.write(batch)); Ok((inserts + deletes) as u32) } diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 09362676b..85f40e048 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -176,7 +176,7 @@ impl JournalDB for RefCountedDB { } } - let r = try!(self.forward.commit_to_batch(&batch)); + let r = try!(self.forward.commit()); try!(self.backing.write(batch)); Ok(r) } diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index 8166dd318..d176d38f6 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -72,13 +72,13 @@ impl OverlayDB { if total_rc < 0 { return Err(From::from(BaseDataError::NegativelyReferencedHash)); } - deletes += if self.put_payload(batch, &key, (back_value, total_rc as u32)) {1} else {0}; + deletes += if self.put_payload_in_batch(batch, &key, (back_value, total_rc as u32)) {1} else {0}; } None => { if rc < 0 { return Err(From::from(BaseDataError::NegativelyReferencedHash)); } - self.put_payload(batch, &key, (value, rc as u32)); + self.put_payload_in_batch(batch, &key, (value, rc as u32)); } }; ret += 1; @@ -116,10 +116,32 @@ impl OverlayDB { /// } /// ``` pub fn commit(&mut self) -> Result { - let batch = DBTransaction::new(); - let r = try!(self.commit_to_batch(&batch)); - try!(self.backing.write(batch)); - Ok(r) + let mut ret = 0u32; + let mut deletes = 0usize; + for i in self.overlay.drain().into_iter() { + let (key, (value, rc)) = i; + if rc != 0 { + match self.payload(&key) { + Some(x) => { + let (back_value, back_rc) = x; + let total_rc: i32 = back_rc as i32 + rc; + if total_rc < 0 { + return Err(From::from(BaseDataError::NegativelyReferencedHash)); + } + deletes += if self.put_payload(&key, (back_value, total_rc as u32)) {1} else {0}; + } + None => { + if rc < 0 { + return Err(From::from(BaseDataError::NegativelyReferencedHash)); + } + self.put_payload(&key, (value, rc as u32)); + } + }; + ret += 1; + } + } + trace!("OverlayDB::commit() deleted {} nodes", deletes); + Ok(ret) } /// Revert all operations on this object (i.e. `insert()`s and `kill()`s) since the @@ -156,7 +178,7 @@ impl OverlayDB { } /// Put the refs and value of the given key, possibly deleting it from the db. - fn put_payload(&self, batch: &DBTransaction, key: &H256, payload: (Bytes, u32)) -> bool { + fn put_payload_in_batch(&self, batch: &DBTransaction, key: &H256, payload: (Bytes, u32)) -> bool { if payload.1 > 0 { let mut s = RlpStream::new_list(2); s.append(&payload.1); @@ -168,6 +190,20 @@ impl OverlayDB { true } } + + /// Put the refs and value of the given key, possibly deleting it from the db. + fn put_payload(&self, key: &H256, payload: (Bytes, u32)) -> bool { + if payload.1 > 0 { + let mut s = RlpStream::new_list(2); + s.append(&payload.1); + s.append(&payload.0); + self.backing.put(&key.bytes(), s.as_raw()).expect("Low-level database error. Some issue with your hard disk?"); + false + } else { + self.backing.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + true + } + } } impl HashDB for OverlayDB { From c5edf237b2c17f56950016f3fcca1c77cfe416b3 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 13 Mar 2016 19:52:37 +0100 Subject: [PATCH 585/753] adding shrink-to-fit --- util/src/keys/directory.rs | 2 ++ util/src/keys/store.rs | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index d0d3393cd..a92bf4593 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -542,6 +542,8 @@ impl KeyDirectory { if removes.is_empty() { return; } let mut cache = self.cache.write().unwrap(); for key in removes { cache.remove(&key); } + + cache.shrink_to_fit(); } /// Reports how many keys are currently cached. diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index e0a505f79..78540bdb0 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -273,13 +273,16 @@ impl SecretStore { /// Makes account unlocks expire and removes unused key files from memory pub fn collect_garbage(&mut self) { + let mut garbage_lock = self.unlocks.write().unwrap(); self.directory.collect_garbage(); let utc = UTC::now(); - let expired_addresses = self.unlocks.read().unwrap().iter() + let expired_addresses = garbage_lock.iter() .filter(|&(_, unlock)| unlock.expires < utc) .map(|(address, _)| address.clone()).collect::>(); - for expired in expired_addresses { self.unlocks.write().unwrap().remove(&expired); } + for expired in expired_addresses { garbage_lock.remove(&expired); } + + garbage_lock.shrink_to_fit(); } } From e2e067cdd07f5d2a5dd18d79d7d36d8b4a93e122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 13 Mar 2016 20:44:25 +0100 Subject: [PATCH 586/753] Bumping clippy --- miner/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 5d265e9a4..b450ece73 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -17,7 +17,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" rayon = "0.3.1" -clippy = { version = "0.0.49", optional = true } +clippy = { version = "0.0.50", optional = true } [features] default = [] From 4cf18c728d972524089b1e6190a47cb22445c542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 13 Mar 2016 20:53:47 +0100 Subject: [PATCH 587/753] Fixing sync invalid sync test --- Cargo.lock | 12 +----------- sync/src/chain.rs | 2 +- sync/src/lib.rs | 1 - 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d68c5c121..8bf57cb6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,16 +93,6 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "clippy" -version = "0.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clippy" version = "0.0.50" @@ -300,7 +290,7 @@ dependencies = [ name = "ethminer" version = "0.9.99" dependencies = [ - "clippy 0.0.49 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", "ethcore-util 0.9.99", diff --git a/sync/src/chain.rs b/sync/src/chain.rs index d06a34764..6045a23d9 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1616,7 +1616,7 @@ mod tests { let mut io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&mut io, &[], &good_blocks, &[], &[]); + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); assert_eq!(sync.miner.status().transaction_queue_future, 0); assert_eq!(sync.miner.status().transaction_queue_pending, 1); sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index c47b74b66..1c87da2de 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -164,7 +164,6 @@ impl NetworkProtocolHandler for EthSync { self.sync.write().unwrap().maintain_sync(&mut NetSyncIo::new(io, self.chain.deref())); } - #[allow(single_match)] fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => { From 13df958f4ae200a0bf2d8a9b913bdd8e6adcbc1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 13 Mar 2016 21:06:24 +0100 Subject: [PATCH 588/753] Fixing warnings --- util/src/journaldb/earlymergedb.rs | 16 +++++++++------- util/src/keys/store.rs | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index 7f0f50da2..7cb00b993 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -171,7 +171,7 @@ impl EarlyMergeDB { trace!(target: "jdb.fine", "replay_keys: (end) refs={:?}", refs); } - fn kill_keys(deletes: &Vec, refs: &mut HashMap, batch: &DBTransaction, from: RemoveFrom, trace: bool) { + fn kill_keys(deletes: &[H256], refs: &mut HashMap, batch: &DBTransaction, from: RemoveFrom, trace: bool) { // with a kill on {queue_refs: 1, in_archive: true}, we have two options: // - convert to {queue_refs: 1, in_archive: false} (i.e. remove it from the conceptual archive) // - convert to {queue_refs: 0, in_archive: true} (i.e. remove it from the conceptual queue) @@ -340,8 +340,10 @@ impl JournalDB for EarlyMergeDB { } } + + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: + // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, n] => [ ... ] @@ -473,7 +475,7 @@ impl JournalDB for EarlyMergeDB { if trace { trace!(target: "jdb.ops", " Finalising: {:?}", inserts); } - for k in inserts.iter() { + for k in &inserts { match refs.get(k).cloned() { None => { // [in archive] -> SHIFT remove -> SHIFT insert None->Some{queue_refs: 1, in_archive: true} -> TAKE remove Some{queue_refs: 1, in_archive: true}->None -> TAKE insert @@ -489,7 +491,7 @@ impl JournalDB for EarlyMergeDB { Self::set_already_in(&batch, k); refs.insert(k.clone(), RefInfo{ queue_refs: x - 1, in_archive: true }); } - Some( RefInfo{queue_refs: _, in_archive: true} ) => { + Some( RefInfo{in_archive: true, ..} ) => { // Invalid! Reinserted the same key twice. warn!("Key {} inserted twice into same fork.", k); } @@ -936,7 +938,7 @@ mod tests { assert!(jdb.can_reconstruct_refs()); assert!(!jdb.exists(&foo)); } - + #[test] fn reopen_test() { let mut dir = ::std::env::temp_dir(); @@ -971,7 +973,7 @@ mod tests { jdb.commit(7, &b"7".sha3(), Some((3, b"3".sha3()))).unwrap(); assert!(jdb.can_reconstruct_refs()); } - + #[test] fn reopen_remove_three() { init_log(); @@ -1025,7 +1027,7 @@ mod tests { assert!(!jdb.exists(&foo)); } } - + #[test] fn reopen_fork() { let mut dir = ::std::env::temp_dir(); diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 610dda9f5..8aba08519 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -363,13 +363,13 @@ impl EncryptedHashMap for SecretStore { } #[cfg(test)] +#[cfg(feature="heavy-tests")] mod vector_tests { use super::{derive_mac,derive_key_iterations}; use common::*; #[test] - #[cfg(feature="heavy-tests")] fn mac_vector() { let password = "testpassword"; let salt = H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(); From 1be92ea8efafd5e4751ba6f2404073a8b72ea0b0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 21:21:30 +0100 Subject: [PATCH 589/753] Fixes and traces for refcountdb. --- util/src/journaldb/refcounteddb.rs | 34 ++++++++++++++++++------------ util/src/overlaydb.rs | 7 ++++++ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 85f40e048..71833533f 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -43,6 +43,7 @@ pub struct RefCountedDB { const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; const DB_VERSION : u32 = 512; +const PADDING : [u8; 10] = [ 0u8; 10 ]; impl RefCountedDB { /// Create a new instance given a `backing` database. @@ -125,15 +126,15 @@ impl JournalDB for RefCountedDB { // of its inserts otherwise. // record new commit's details. - let batch = DBTransaction::new(); { let mut index = 0usize; let mut last; while try!(self.backing.get({ - let mut r = RlpStream::new_list(2); + let mut r = RlpStream::new_list(3); r.append(&now); r.append(&index); + r.append(&&PADDING[..]); last = r.drain(); &last })).is_some() { @@ -145,11 +146,14 @@ impl JournalDB for RefCountedDB { r.append(&self.inserts); r.append(&self.removes); try!(self.backing.put(&last, r.as_raw())); + + trace!(target: "rcdb", "new journal for time #{}.{} => {}: inserts={:?}, removes={:?}", now, index, id, self.inserts, self.removes); + self.inserts.clear(); self.removes.clear(); if self.latest_era.map_or(true, |e| now > e) { - try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + try!(self.backing.put(&LATEST_ERA_KEY, &encode(&now))); self.latest_era = Some(now); } } @@ -158,26 +162,30 @@ impl JournalDB for RefCountedDB { if let Some((end_era, canon_id)) = end { let mut index = 0usize; let mut last; - while let Some(rlp_data) = try!(self.backing.get({ - let mut r = RlpStream::new_list(2); - r.append(&end_era); - r.append(&index); - last = r.drain(); - &last - })) { + while let Some(rlp_data) = { +// trace!(target: "rcdb", "checking for journal #{}.{}", end_era, index); + try!(self.backing.get({ + let mut r = RlpStream::new_list(3); + r.append(&end_era); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })) + } { let rlp = Rlp::new(&rlp_data); - let to_remove: Vec = rlp.val_at(if canon_id == rlp.val_at(0) {2} else {1}); + let our_id: H256 = rlp.val_at(0); + let to_remove: Vec = rlp.val_at(if canon_id == our_id {2} else {1}); + trace!(target: "rcdb", "delete journal for time #{}.{}=>{}, (canon was {}): deleting {:?}", end_era, index, our_id, canon_id, to_remove); for i in &to_remove { self.forward.remove(i); } try!(self.backing.delete(&last)); - trace!("RefCountedDB: delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, to_remove.len()); index += 1; } } let r = try!(self.forward.commit()); - try!(self.backing.write(batch)); Ok(r) } } diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index d176d38f6..5704950ed 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -70,12 +70,14 @@ impl OverlayDB { let (back_value, back_rc) = x; let total_rc: i32 = back_rc as i32 + rc; if total_rc < 0 { + warn!("NEGATIVELY REFERENCED HASH {:?}", key); return Err(From::from(BaseDataError::NegativelyReferencedHash)); } deletes += if self.put_payload_in_batch(batch, &key, (back_value, total_rc as u32)) {1} else {0}; } None => { if rc < 0 { + warn!("NEGATIVELY REFERENCED HASH {:?}", key); return Err(From::from(BaseDataError::NegativelyReferencedHash)); } self.put_payload_in_batch(batch, &key, (value, rc as u32)); @@ -126,12 +128,14 @@ impl OverlayDB { let (back_value, back_rc) = x; let total_rc: i32 = back_rc as i32 + rc; if total_rc < 0 { + warn!("NEGATIVELY REFERENCED HASH {:?}", key); return Err(From::from(BaseDataError::NegativelyReferencedHash)); } deletes += if self.put_payload(&key, (back_value, total_rc as u32)) {1} else {0}; } None => { if rc < 0 { + warn!("NEGATIVELY REFERENCED HASH {:?}", key); return Err(From::from(BaseDataError::NegativelyReferencedHash)); } self.put_payload(&key, (value, rc as u32)); @@ -167,6 +171,9 @@ impl OverlayDB { /// ``` pub fn revert(&mut self) { self.overlay.clear(); } + /// Get the number of references that would be committed. + pub fn commit_refs(&self, key: &H256) -> i32 { self.overlay.raw(&key).map_or(0, |&(_, refs)| refs) } + /// Get the refs and value of the given key. fn payload(&self, key: &H256) -> Option<(Bytes, u32)> { self.backing.get(&key.bytes()) From 420f473f90d3908d7a3f3cd0c245b797ae64c9f1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 13 Mar 2016 21:28:57 +0100 Subject: [PATCH 590/753] Check for NULL_RLP in AccountDB --- ethcore/src/account_db.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index 026e813f5..f95ec53a1 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -97,6 +97,9 @@ impl<'db> HashDB for AccountDBMut<'db>{ } fn insert(&mut self, value: &[u8]) -> H256 { + if value == &NULL_RLP { + return SHA3_NULL_RLP.clone(); + } let k = value.sha3(); let ak = combine_key(&self.address, &k); self.db.emplace(ak, value.to_vec()); @@ -104,11 +107,17 @@ impl<'db> HashDB for AccountDBMut<'db>{ } fn emplace(&mut self, key: H256, value: Bytes) { + if key == SHA3_NULL_RLP { + return; + } let key = combine_key(&self.address, &key); self.db.emplace(key, value.to_vec()) } fn kill(&mut self, key: &H256) { + if key == &SHA3_NULL_RLP { + return; + } let key = combine_key(&self.address, key); self.db.kill(&key) } From fd834084f9f80c2c447e7424e74dddf9ed7e415d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 13 Mar 2016 21:39:23 +0100 Subject: [PATCH 591/753] unknonw lint --- util/src/table.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/table.rs b/util/src/table.rs index 5ba572289..c3b2006cf 100644 --- a/util/src/table.rs +++ b/util/src/table.rs @@ -40,7 +40,7 @@ impl Default for Table } // There is default but clippy does not detect it? -#[allow(new_without_default)] +#[cfg_attr(feature="dev", allow(new_without_default))] impl Table where Row: Eq + Hash + Clone, Col: Eq + Hash { From 26f41b711c30dc4a0cd3264cf38dd47f7b6aefc7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 21:54:06 +0100 Subject: [PATCH 592/753] Bring back batching. --- util/src/error.rs | 3 ++- util/src/journaldb/refcounteddb.rs | 10 ++++++---- util/src/overlaydb.rs | 12 ++++-------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/util/src/error.rs b/util/src/error.rs index 68aa3e648..409cc0e5d 100644 --- a/util/src/error.rs +++ b/util/src/error.rs @@ -21,12 +21,13 @@ use network::NetworkError; use rlp::DecoderError; use io; use std::fmt; +use hash::H256; #[derive(Debug)] /// Error in database subsystem. pub enum BaseDataError { /// An entry was removed more times than inserted. - NegativelyReferencedHash, + NegativelyReferencedHash(H256), } #[derive(Debug)] diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 71833533f..590964247 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -126,6 +126,7 @@ impl JournalDB for RefCountedDB { // of its inserts otherwise. // record new commit's details. + let batch = DBTransaction::new(); { let mut index = 0usize; let mut last; @@ -145,7 +146,7 @@ impl JournalDB for RefCountedDB { r.append(id); r.append(&self.inserts); r.append(&self.removes); - try!(self.backing.put(&last, r.as_raw())); + try!(batch.put(&last, r.as_raw())); trace!(target: "rcdb", "new journal for time #{}.{} => {}: inserts={:?}, removes={:?}", now, index, id, self.inserts, self.removes); @@ -153,7 +154,7 @@ impl JournalDB for RefCountedDB { self.removes.clear(); if self.latest_era.map_or(true, |e| now > e) { - try!(self.backing.put(&LATEST_ERA_KEY, &encode(&now))); + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); self.latest_era = Some(now); } } @@ -180,12 +181,13 @@ impl JournalDB for RefCountedDB { for i in &to_remove { self.forward.remove(i); } - try!(self.backing.delete(&last)); + try!(batch.delete(&last)); index += 1; } } - let r = try!(self.forward.commit()); + let r = try!(self.forward.commit_to_batch(&batch)); + try!(self.backing.write(batch)); Ok(r) } } diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index 5704950ed..b5dec75e2 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -70,15 +70,13 @@ impl OverlayDB { let (back_value, back_rc) = x; let total_rc: i32 = back_rc as i32 + rc; if total_rc < 0 { - warn!("NEGATIVELY REFERENCED HASH {:?}", key); - return Err(From::from(BaseDataError::NegativelyReferencedHash)); + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); } deletes += if self.put_payload_in_batch(batch, &key, (back_value, total_rc as u32)) {1} else {0}; } None => { if rc < 0 { - warn!("NEGATIVELY REFERENCED HASH {:?}", key); - return Err(From::from(BaseDataError::NegativelyReferencedHash)); + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); } self.put_payload_in_batch(batch, &key, (value, rc as u32)); } @@ -128,15 +126,13 @@ impl OverlayDB { let (back_value, back_rc) = x; let total_rc: i32 = back_rc as i32 + rc; if total_rc < 0 { - warn!("NEGATIVELY REFERENCED HASH {:?}", key); - return Err(From::from(BaseDataError::NegativelyReferencedHash)); + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); } deletes += if self.put_payload(&key, (back_value, total_rc as u32)) {1} else {0}; } None => { if rc < 0 { - warn!("NEGATIVELY REFERENCED HASH {:?}", key); - return Err(From::from(BaseDataError::NegativelyReferencedHash)); + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); } self.put_payload(&key, (value, rc as u32)); } From 8fd8f687ee0414684217b815147be40dcc8bdb06 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 13 Mar 2016 23:12:47 +0100 Subject: [PATCH 593/753] Remove EarlyMerge from user docs. --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index f2c661958..db9070493 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -83,7 +83,7 @@ Protocol Options: --testnet Equivalent to --chain testnet (geth-compatible). --networkid INDEX Override the network identifier from the chain we are on. --pruning METHOD Configure pruning of the state/storage trie. METHOD may be one of: archive, - basic (experimental), light (experimental), fast (experimental) [default: archive]. + basic (experimental), fast (experimental) [default: archive]. -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] From 45c3600d5ab2012f0f7c083ec774c77c76c5d57c Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 13 Mar 2016 23:20:26 +0100 Subject: [PATCH 594/753] Fixed splitting Neighbours packet --- util/src/network/discovery.rs | 43 +++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index a381b49f8..f5c4592f0 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -407,25 +407,37 @@ impl Discovery { let target: NodeId = try!(rlp.val_at(0)); let timestamp: u64 = try!(rlp.val_at(1)); try!(self.check_timestamp(timestamp)); - let limit = (MAX_DATAGRAM_SIZE - 109) / 90; let nearest = Discovery::nearest_node_entries(&target, &self.node_buckets); if nearest.is_empty() { return Ok(None); } + let mut packets = Discovery::prepare_neighbours_packets(&nearest); + for p in packets.drain(..) { + self.send_packet(PACKET_NEIGHBOURS, &from, &p); + } + trace!(target: "discovery", "Sent {} Neighbours to {:?}", nearest.len(), &from); + Ok(None) + } + + fn prepare_neighbours_packets(nearest: &[NodeEntry]) -> Vec { + let mut packets = Vec::new(); let mut rlp = RlpStream::new_list(1); - rlp.begin_list(cmp::min(limit, nearest.len())); + let limit = (MAX_DATAGRAM_SIZE - 109) / 90; + let mut count = cmp::min(limit, nearest.len()); + rlp.begin_list(count); for n in 0 .. nearest.len() { rlp.begin_list(4); nearest[n].endpoint.to_rlp(&mut rlp); rlp.append(&nearest[n].id); - if (n + 1) % limit == 0 || n == nearest.len() - 1 { - self.send_packet(PACKET_NEIGHBOURS, &from, &rlp.drain()); - trace!(target: "discovery", "Sent {} Neighbours to {:?}", n, &from); + count -= 1; + if count == 0 { + packets.push(rlp.out()); rlp = RlpStream::new_list(1); - rlp.begin_list(cmp::min(limit, nearest.len() - n)); + count = cmp::min(limit, nearest.len() - n); + rlp.begin_list(count); } } - Ok(None) + packets } fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { @@ -506,6 +518,23 @@ mod tests { use crypto::KeyPair; use std::str::FromStr; use rustc_serialize::hex::FromHex; + use rlp::*; + + #[test] + fn find_node() { + let mut nearest = Vec::new(); + let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); + for _ in 0..1000 { + nearest.push( NodeEntry { id: node.id.clone(), endpoint: node.endpoint.clone() }); + } + + let packets = Discovery::prepare_neighbours_packets(&nearest); + assert_eq!(packets.len(), 76); + for p in &packets { + assert!(p.len() > 1280/2); + assert!(p.len() <= 1280); + } + } #[test] fn discovery() { From 615e03542ebb6ff4f60262a3cf7426c1ce74f821 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 14 Mar 2016 00:41:25 +0100 Subject: [PATCH 595/753] Use slice.chunks --- util/src/network/discovery.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index f5c4592f0..6fda99cdb 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -18,7 +18,6 @@ use bytes::Bytes; use std::net::SocketAddr; use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; use std::mem; -use std::cmp; use std::default::Default; use mio::*; use mio::udp::*; @@ -420,24 +419,19 @@ impl Discovery { } fn prepare_neighbours_packets(nearest: &[NodeEntry]) -> Vec { - let mut packets = Vec::new(); - let mut rlp = RlpStream::new_list(1); let limit = (MAX_DATAGRAM_SIZE - 109) / 90; - let mut count = cmp::min(limit, nearest.len()); - rlp.begin_list(count); - for n in 0 .. nearest.len() { - rlp.begin_list(4); - nearest[n].endpoint.to_rlp(&mut rlp); - rlp.append(&nearest[n].id); - count -= 1; - if count == 0 { - packets.push(rlp.out()); - rlp = RlpStream::new_list(1); - count = cmp::min(limit, nearest.len() - n); - rlp.begin_list(count); + let chunks = nearest.chunks(limit); + let packets = chunks.map(|c| { + let mut rlp = RlpStream::new_list(1); + rlp.begin_list(c.len()); + for n in 0 .. c.len() { + rlp.begin_list(4); + c[n].endpoint.to_rlp(&mut rlp); + rlp.append(&c[n].id); } - } - packets + rlp.out() + }); + packets.collect() } fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { @@ -529,11 +523,12 @@ mod tests { } let packets = Discovery::prepare_neighbours_packets(&nearest); - assert_eq!(packets.len(), 76); - for p in &packets { + assert_eq!(packets.len(), 77); + for p in &packets[0..76] { assert!(p.len() > 1280/2); assert!(p.len() <= 1280); } + assert!(packets.last().unwrap().len() > 0); } #[test] From 1957a1496163f0a33a8ff8d6aff9261a5ad4ee20 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 14 Mar 2016 00:48:43 +0100 Subject: [PATCH 596/753] personal tests setup --- rpc/src/v1/tests/mod.rs | 1 + rpc/src/v1/tests/personal.rs | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 rpc/src/v1/tests/personal.rs diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 3374bad36..21085a0fd 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -20,3 +20,4 @@ mod eth; mod net; mod web3; mod helpers; +mod personal; diff --git a/rpc/src/v1/tests/personal.rs b/rpc/src/v1/tests/personal.rs new file mode 100644 index 000000000..440a95a6f --- /dev/null +++ b/rpc/src/v1/tests/personal.rs @@ -0,0 +1,47 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use jsonrpc_core::IoHandler; +use v1::tests::helpers::{TestAccount, TestAccountProvider}; +use v1::{PersonalClient, Personal}; +use util::numbers::*; +use std::collections::*; + +fn accounts_provider() -> Arc { + let mut accounts = HashMap::new(); + accounts.insert(Address::from(1), TestAccount::new("test")); + let ap = TestAccountProvider::new(accounts); + Arc::new(ap) +} + +fn setup() -> (Arc, IoHandler) { + let test_provider = accounts_provider(); + let personal = PersonalClient::new(&test_provider); + let io = IoHandler::new(); + io.add_delegate(personal.to_delegate()); + (test_provider, io) +} + +#[test] +fn accounts() { + let (_test_provider, io) = setup(); + + let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} From 2d1a837a8b4ff14b43ac090bc5f1a22f0cc12479 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 14 Mar 2016 00:52:31 +0100 Subject: [PATCH 597/753] docopts cleanups. one for @LefterisJP: 80-character line for docopts. --- parity/main.rs | 116 +++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 51 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index db9070493..3473f44b1 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -78,72 +78,86 @@ Usage: parity [options] Protocol Options: - --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file - or olympic, frontier, homestead, mainnet, morden, or testnet [default: homestead]. - --testnet Equivalent to --chain testnet (geth-compatible). - --networkid INDEX Override the network identifier from the chain we are on. - --pruning METHOD Configure pruning of the state/storage trie. METHOD may be one of: archive, - basic (experimental), fast (experimental) [default: archive]. - -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] - --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] - --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] + --chain CHAIN Specify the blockchain type. CHAIN may be either a + JSON chain specification file or olympic, frontier, + homestead, mainnet, morden, or testnet + [default: homestead]. + -d --db-path PATH Specify the database & configuration directory path + [default: $HOME/.parity]. + --keys-path PATH Specify the path for JSON key files to be found + [default: $HOME/.web3/keys]. --identity NAME Specify your node's name. Networking Options: - --port PORT Override the port on which the node should listen [default: 30303]. + --port PORT Override the port on which the node should listen + [default: 30303]. --peers NUM Try to maintain that many peers [default: 25]. - --nat METHOD Specify method to use for determining public address. Must be one of: any, none, - upnp, extip:(IP) [default: any]. - --bootnodes NODES Specify additional comma-separated bootnodes. - --no-bootstrap Don't bother trying to connect to standard bootnodes. + --nat METHOD Specify method to use for determining public + address. Must be one of: any, none, upnp, + extip: [default: any]. + --network-id INDEX Override the network identifier from the chain we + are on. + --bootnodes NODES Override the bootnodes from our chain. NODES should + be comma-delimited enodes. --no-discovery Disable new peer discovery. - --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. + --node-key KEY Specify node secret key, either as 64-character hex + string or input to SHA3 operation. API and Console Options: -j --jsonrpc Enable the JSON-RPC API sever. - --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API server [default: 127.0.0.1]. - --jsonrpc-port PORT Specify the port portion of the JSONRPC API server [default: 8545]. - --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. - --jsonrpc-apis APIS Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited - list of API name. Possible name are web3, eth and net. [default: web3,eth,net,personal]. - - --rpc Equivalent to --jsonrpc (geth-compatible). - --rpcaddr HOST Equivalent to --jsonrpc-addr HOST (geth-compatible). - --rpcport PORT Equivalent to --jsonrpc-port PORT (geth-compatible). - --rpcapi APIS Equivalent to --jsonrpc-apis APIS (geth-compatible). - --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). + --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API + server [default: 127.0.0.1]. + --jsonrpc-port PORT Specify the port portion of the JSONRPC API server + [default: 8545]. + --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses + [default: null]. + --jsonrpc-apis APIS Specify the APIs available through the JSONRPC + interface. APIS is a comma-delimited list of API + name. Possible name are web3, eth and net. + [default: web3,eth,net,personal]. Sealing/Mining Options: - --gas-price WEI Minimum amount of Wei to be paid for a transaction to be accepted for mining [default: 20000000000]. - --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards - from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. - --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. + --gas-price WEI Minimum amount of Wei to be paid for a transaction + to be accepted for mining [default: 20000000000]. + --author ADDRESS Specify the block author (aka "coinbase") address + for sending block rewards from sealed blocks + [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. + --extra-data STRING Specify a custom extra-data for authored blocks, no + more than 32 characters. -Memory Footprint Options: - --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. - --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. - --queue-max-size BYTES Specify the maximum size of memory to use for block queue [default: 52428800]. - --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with - other cache options (geth-compatible). +Footprint Options: + --pruning METHOD Configure pruning of the state/storage trie. METHOD + may be one of: archive, basic (experimental), fast + (experimental) [default: archive]. + --cache-pref-size BYTES Specify the prefered size of the blockchain cache in + bytes [default: 16384]. + --cache-max-size BYTES Specify the maximum size of the blockchain cache in + bytes [default: 262144]. + --queue-max-size BYTES Specify the maximum size of memory to use for block + queue [default: 52428800]. + --cache MEGABYTES Set total amount of discretionary memory to use for + the entire system, overrides other cache and queue + options. -Geth-Compatibility Options +Geth-compatibility Options: --datadir PATH Equivalent to --db-path PATH. --testnet Equivalent to --chain testnet. - --networkid INDEX Override the network identifier from the chain we are on. + --networkid INDEX Equivalent to --network-id INDEX. + --maxpeers COUNT Equivalent to --peers COUNT. + --nodekey KEY Equivalent to --node-key KEY. + --nodiscover Equivalent to --no-discovery. --rpc Equivalent to --jsonrpc. --rpcaddr HOST Equivalent to --jsonrpc-addr HOST. --rpcport PORT Equivalent to --jsonrpc-port PORT. --rpcapi APIS Equivalent to --jsonrpc-apis APIS. --rpccorsdomain URL Equivalent to --jsonrpc-cors URL. - --maxpeers COUNT Equivalent to --peers COUNT. - --nodekey KEY Equivalent to --node-key KEY. - --nodiscover Equivalent to --no-discovery. --gasprice WEI Equivalent to --gas-price WEI. --etherbase ADDRESS Equivalent to --author ADDRESS. --extradata STRING Equivalent to --extra-data STRING. Miscellaneous Options: - -l --logging LOGGING Specify the logging level. Must conform to the same format as RUST_LOG. + -l --logging LOGGING Specify the logging level. Must conform to the same + format as RUST_LOG. -v --version Show information about version. -h --help Show this screen. "#; @@ -161,8 +175,8 @@ struct Args { flag_cache: Option, flag_keys_path: String, flag_bootnodes: Option, + flag_network_id: Option, flag_pruning: String, - flag_no_bootstrap: bool, flag_port: u16, flag_peers: usize, flag_no_discovery: bool, @@ -345,15 +359,15 @@ impl Configuration { } fn init_nodes(&self, spec: &Spec) -> Vec { - let mut r = if self.args.flag_no_bootstrap { Vec::new() } else { spec.nodes().clone() }; - if let Some(ref x) = self.args.flag_bootnodes { - r.extend(x.split(',').map(|s| { + match self.args.flag_bootnodes { + Some(ref x) if x.len() > 0 => x.split(',').map(|s| { Self::normalize_enode(s).unwrap_or_else(|| { die!("{}: Invalid node address format given for a boot node.", s) }) - })); + }).collect(), + Some(_) => Vec::new(), + None => spec.nodes().clone(), } - r } #[cfg_attr(feature="dev", allow(useless_format))] @@ -390,7 +404,7 @@ impl Configuration { match self.args.flag_cache { Some(mb) => { client_config.blockchain.max_cache_size = mb * 1024 * 1024; - client_config.blockchain.pref_cache_size = client_config.blockchain.max_cache_size / 2; + client_config.blockchain.pref_cache_size = client_config.blockchain.max_cache_size * 3 / 4; } None => { client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; @@ -411,8 +425,8 @@ impl Configuration { fn sync_config(&self, spec: &Spec) -> SyncConfig { let mut sync_config = SyncConfig::default(); - sync_config.network_id = self.args.flag_networkid.as_ref().map_or(spec.network_id(), |id| { - U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --networkid", id)) + sync_config.network_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref()).map_or(spec.network_id(), |id| { + U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --network-id/--networkid", id)) }); sync_config } From 9e7ff2c00e0505b7ef6622935e2ee203bc3202f3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 14 Mar 2016 00:13:54 +0100 Subject: [PATCH 598/753] Version 1.1 --- Cargo.lock | 73 ++++++++++++++++++++++++--------------------- Cargo.toml | 2 +- devtools/Cargo.toml | 2 +- ethash/Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- evmjit/Cargo.toml | 2 +- miner/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- util/Cargo.toml | 2 +- util/src/misc.rs | 4 +-- 11 files changed, 50 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bf57cb6a..dfe37dbb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,18 +1,18 @@ [root] name = "parity" -version = "0.9.99" +version = "1.1.0" dependencies = [ "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.99", - "ethcore-devtools 0.9.99", - "ethcore-rpc 0.9.99", - "ethcore-util 0.9.99", - "ethminer 0.9.99", - "ethsync 0.9.99", + "ethcore 1.1.0", + "ethcore-devtools 1.1.0", + "ethcore-rpc 1.1.0", + "ethcore-util 1.1.0", + "ethminer 1.1.0", + "ethsync 1.1.0", "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -162,7 +162,7 @@ name = "docopt" version = "0.6.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -178,7 +178,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -197,7 +197,7 @@ dependencies = [ [[package]] name = "ethash" -version = "0.9.99" +version = "1.1.0" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -206,14 +206,14 @@ dependencies = [ [[package]] name = "ethcore" -version = "0.9.99" +version = "1.1.0" dependencies = [ "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 0.9.99", - "ethcore-devtools 0.9.99", - "ethcore-util 0.9.99", + "ethash 1.1.0", + "ethcore-devtools 1.1.0", + "ethcore-util 1.1.0", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -225,21 +225,21 @@ dependencies = [ [[package]] name = "ethcore-devtools" -version = "0.9.99" +version = "1.1.0" dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ethcore-rpc" -version = "0.9.99" +version = "1.1.0" dependencies = [ "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "ethash 0.9.99", - "ethcore 0.9.99", - "ethcore-util 0.9.99", - "ethminer 0.9.99", - "ethsync 0.9.99", + "ethash 1.1.0", + "ethcore 1.1.0", + "ethcore-util 1.1.0", + "ethminer 1.1.0", + "ethsync 1.1.0", "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -253,7 +253,7 @@ dependencies = [ [[package]] name = "ethcore-util" -version = "0.9.99" +version = "1.1.0" dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", @@ -263,7 +263,7 @@ dependencies = [ "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", - "ethcore-devtools 0.9.99", + "ethcore-devtools 1.1.0", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -288,12 +288,12 @@ dependencies = [ [[package]] name = "ethminer" -version = "0.9.99" +version = "1.1.0" dependencies = [ "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.99", - "ethcore-util 0.9.99", + "ethcore 1.1.0", + "ethcore-util 1.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -302,13 +302,13 @@ dependencies = [ [[package]] name = "ethsync" -version = "0.9.99" +version = "1.1.0" dependencies = [ "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.99", - "ethcore-util 0.9.99", - "ethminer 0.9.99", + "ethcore 1.1.0", + "ethcore-util 1.1.0", + "ethminer 1.1.0", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -343,7 +343,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -406,7 +406,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -687,12 +687,12 @@ dependencies = [ [[package]] name = "regex" -version = "0.1.55" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -701,6 +701,11 @@ name = "regex-syntax" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex-syntax" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rocksdb" version = "0.4.3" diff --git a/Cargo.toml b/Cargo.toml index 351041119..782dd1c79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore client." name = "parity" -version = "0.9.99" +version = "1.1.0" license = "GPL-3.0" authors = ["Ethcore "] build = "build.rs" diff --git a/devtools/Cargo.toml b/devtools/Cargo.toml index ce0260936..19178fbfe 100644 --- a/devtools/Cargo.toml +++ b/devtools/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore development/test/build tools" homepage = "http://ethcore.io" license = "GPL-3.0" name = "ethcore-devtools" -version = "0.9.99" +version = "1.1.0" authors = ["Ethcore "] [dependencies] diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index e2a2ec4d8..70d08249c 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ethash" -version = "0.9.99" +version = "1.1.0" authors = ["arkpar "] [dependencies] diff --git a/evmjit/Cargo.toml b/evmjit/Cargo.toml index 9449af82d..6586a360e 100644 --- a/evmjit/Cargo.toml +++ b/evmjit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evmjit" -version = "0.9.99" +version = "1.1.0" authors = ["debris "] [lib] diff --git a/miner/Cargo.toml b/miner/Cargo.toml index b450ece73..cd56aee9e 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethminer library" homepage = "http://ethcore.io" license = "GPL-3.0" name = "ethminer" -version = "0.9.99" +version = "1.1.0" authors = ["Ethcore "] build = "build.rs" diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index fa89041d8..88b69e82c 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore jsonrpc" name = "ethcore-rpc" -version = "0.9.99" +version = "1.1.0" license = "GPL-3.0" authors = ["Ethcore "] build = "build.rs" diff --git a/util/src/misc.rs b/util/src/misc.rs index 39ccbf2da..8dcd25988 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -70,7 +70,7 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { - format!("Parity/v{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) + format!("Parity/v{}-unstable-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) } /// Get the standard version data for this software. @@ -85,4 +85,4 @@ pub fn version_data() -> Bytes { s.append(&format!("{}", rustc_version::version())); s.append(&&Target::os()[0..2]); s.out() -} \ No newline at end of file +} From 2117d363e23b4d159de9d76b435fd6baacfed744 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 14 Mar 2016 01:06:42 +0100 Subject: [PATCH 599/753] new account test & fix --- rpc/src/v1/impls/personal.rs | 2 +- rpc/src/v1/tests/helpers/account_provider.rs | 10 ++++++++-- rpc/src/v1/tests/personal.rs | 12 ++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 0cd3f0040..2822059d6 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -49,7 +49,7 @@ impl Personal for PersonalClient where A: AccountProvider + 'static { |(pass, )| { let store = take_weak!(self.accounts); match store.new_account(&pass) { - Ok(address) => Ok(Value::String(format!("{:?}", address))), + Ok(address) => Ok(Value::String(format!("0x{:?}", address))), Err(_) => Err(Error::internal_error()) } } diff --git a/rpc/src/v1/tests/helpers/account_provider.rs b/rpc/src/v1/tests/helpers/account_provider.rs index 66f085f74..ce5b76b44 100644 --- a/rpc/src/v1/tests/helpers/account_provider.rs +++ b/rpc/src/v1/tests/helpers/account_provider.rs @@ -42,6 +42,7 @@ impl TestAccount { /// Test account provider. pub struct TestAccountProvider { accounts: RwLock>, + pub adds: RwLock>, } impl TestAccountProvider { @@ -49,6 +50,7 @@ impl TestAccountProvider { pub fn new(accounts: HashMap) -> Self { TestAccountProvider { accounts: RwLock::new(accounts), + adds: RwLock::new(vec![]), } } } @@ -69,9 +71,13 @@ impl AccountProvider for TestAccountProvider { } } - fn new_account(&self, _pass: &str) -> Result { - unimplemented!() + fn new_account(&self, pass: &str) -> Result { + let mut adds = self.adds.write().unwrap(); + let address = Address::from(adds.len() as u64 + 2); + adds.push(pass.to_owned()); + Ok(address) } + fn account_secret(&self, _account: &Address) -> Result { unimplemented!() } diff --git a/rpc/src/v1/tests/personal.rs b/rpc/src/v1/tests/personal.rs index 440a95a6f..261527c47 100644 --- a/rpc/src/v1/tests/personal.rs +++ b/rpc/src/v1/tests/personal.rs @@ -45,3 +45,15 @@ fn accounts() { assert_eq!(io.handle_request(request), Some(response.to_owned())); } + + +#[test] +fn new_account() { + let (_test_provider, io) = setup(); + + let request = r#"{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["pass"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000002","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} + From 7bc3c0b0269a007f0b0ff1d69ba318a97b280793 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 14 Mar 2016 01:27:27 +0100 Subject: [PATCH 600/753] Removed rocksdb build dependency --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c614ca5d..6ae41379e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,10 +33,6 @@ addons: - libcurl4-openssl-dev - libelf-dev - libdw-dev -before_script: | - sudo add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && - sudo apt-get update && - sudo apt-get install -y --force-yes librocksdb script: - cargo build --release --verbose ${FEATURES} - cargo test --release --verbose ${FEATURES} ${TARGETS} From f6b7884a1dcdd6382f522ae38c4f6d29222f40c7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 14 Mar 2016 02:00:22 +0100 Subject: [PATCH 601/753] Allow configuration of target gas limit. --- ethcore/src/block.rs | 10 +++++----- ethcore/src/client/client.rs | 5 ++--- ethcore/src/client/mod.rs | 2 +- ethcore/src/client/test_client.rs | 2 +- ethcore/src/engine.rs | 2 +- ethcore/src/ethereum/ethash.rs | 7 +++---- miner/src/miner.rs | 19 +++++++++++++++++-- parity/main.rs | 10 ++++++++++ 8 files changed, 40 insertions(+), 17 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 7eb34670f..6f3986391 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -171,7 +171,7 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new(engine: &'x Engine, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, extra_data: Bytes) -> Self { + pub fn new(engine: &'x Engine, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self { let mut r = OpenBlock { block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), engine: engine, @@ -185,7 +185,7 @@ impl<'x> OpenBlock<'x> { r.block.base.header.extra_data = extra_data; r.block.base.header.note_dirty(); - engine.populate_from_parent(&mut r.block.base.header, parent); + engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target); engine.on_new_block(&mut r.block); r } @@ -347,7 +347,7 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } } - let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), header.extra_data().clone()); + let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone()); b.set_difficulty(*header.difficulty()); b.set_gas_limit(*header.gas_limit()); b.set_timestamp(header.timestamp()); @@ -391,7 +391,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = b.close(); let _ = b.seal(engine.deref(), vec![]); } @@ -405,7 +405,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); - let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(engine.deref(), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d748cc4ee..cbea020ba 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -380,15 +380,13 @@ impl Client where V: Verifier { } impl BlockChainClient for Client where V: Verifier { - - // TODO [todr] Should be moved to miner crate eventually. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result { block.try_seal(self.engine.deref().deref(), seal) } // TODO [todr] Should be moved to miner crate eventually. - fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option { + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> Option { let engine = self.engine.deref().deref(); let h = self.chain.best_block_hash(); @@ -398,6 +396,7 @@ impl BlockChainClient for Client where V: Verifier { match self.chain.block_header(&h) { Some(ref x) => x, None => {return None} }, self.build_last_hashes(h.clone()), author, + gas_floor_target, extra_data, ); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index e46d0b570..88e07d0b1 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -110,7 +110,7 @@ pub trait BlockChainClient : Sync + Send { // TODO [todr] Should be moved to miner crate eventually. /// Returns ClosedBlock prepared for sealing. - fn prepare_sealing(&self, author: Address, extra_data: Bytes, transactions: Vec) -> Option; + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> Option; // TODO [todr] Should be moved to miner crate eventually. /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 140b8d91f..d6a5707e5 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -215,7 +215,7 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn prepare_sealing(&self, _author: Address, _extra_data: Bytes, _transactions: Vec) -> Option { + fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> Option { unimplemented!() } diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index 83e1986fd..0b2ce8ae2 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -85,7 +85,7 @@ pub trait Engine : Sync + Send { /// Don't forget to call Super::populate_from_parent when subclassing & overriding. // TODO: consider including State in the params. - fn populate_from_parent(&self, header: &mut Header, parent: &Header) { + fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256) { header.difficulty = parent.difficulty; header.gas_limit = parent.gas_limit; header.note_dirty(); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index a882f66ae..406777251 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -92,10 +92,9 @@ impl Engine for Ethash { } } - fn populate_from_parent(&self, header: &mut Header, parent: &Header) { + fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256) { header.difficulty = self.calculate_difficuty(header, parent); header.gas_limit = { - let gas_floor_target: U256 = x!(3141562); let gas_limit = parent.gas_limit; let bound_divisor = self.u256_param("gasLimitBoundDivisor"); if gas_limit < gas_floor_target { @@ -300,7 +299,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); + let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -313,7 +312,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); + let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let mut uncle = Header::new(); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); uncle.author = uncle_author.clone(); diff --git a/miner/src/miner.rs b/miner/src/miner.rs index ad403150d..43f11f9c4 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -19,7 +19,7 @@ use std::sync::{Mutex, RwLock, Arc}; use std::sync::atomic; use std::sync::atomic::AtomicBool; -use util::{H256, U256, Address, Bytes}; +use util::{H256, U256, Address, Bytes, Uint}; use ethcore::views::{BlockView}; use ethcore::client::{BlockChainClient, BlockId}; use ethcore::block::{ClosedBlock}; @@ -34,8 +34,10 @@ pub struct Miner { // for sealing... sealing_enabled: AtomicBool, sealing_block: Mutex>, + gas_floor_target: RwLock, author: RwLock
, extra_data: RwLock, + } impl Default for Miner { @@ -44,6 +46,7 @@ impl Default for Miner { transaction_queue: Mutex::new(TransactionQueue::new()), sealing_enabled: AtomicBool::new(false), sealing_block: Mutex::new(None), + gas_floor_target: RwLock::new(U256::zero()), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), } @@ -66,6 +69,11 @@ impl Miner { self.extra_data.read().unwrap().clone() } + /// Get the extra_data that we will seal blocks wuth. + fn gas_floor_target(&self) -> U256 { + self.gas_floor_target.read().unwrap().clone() + } + /// Set the author that we will seal blocks as. pub fn set_author(&self, author: Address) { *self.author.write().unwrap() = author; @@ -76,6 +84,11 @@ impl Miner { *self.extra_data.write().unwrap() = extra_data; } + /// Set the gas limit we wish to target when sealing a new block. + pub fn set_gas_floor_target(&self, target: U256) { + *self.gas_floor_target.write().unwrap() = target; + } + /// Set minimal gas price of transaction to be accepted for mining. pub fn set_minimal_gas_price(&self, min_gas_price: U256) { self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price); @@ -110,12 +123,14 @@ impl MinerService for Miner { fn prepare_sealing(&self, chain: &BlockChainClient) { let no_of_transactions = 128; + // TODO: should select transactions orm queue according to gas limit of block. let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); let b = chain.prepare_sealing( self.author(), + self.gas_floor_target(), self.extra_data(), - transactions, + transactions ); *self.sealing_block.lock().unwrap() = b; } diff --git a/parity/main.rs b/parity/main.rs index 8562b416d..0039d2ba6 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -115,6 +115,7 @@ API and Console Options: Sealing/Mining Options: --gas-price WEI Minimum amount of Wei to be paid for a transaction to be accepted for mining [default: 20000000000]. + --gas-floor-target GAS Amount of gas per block to target when sealing a new block [default: 4712388]. --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. @@ -178,6 +179,7 @@ struct Args { flag_jsonrpc_apis: String, flag_author: String, flag_gas_price: String, + flag_gas_floor_target: String, flag_extra_data: Option, flag_logging: Option, flag_version: bool, @@ -303,6 +305,13 @@ impl Configuration { }) } + fn gas_floor_target(&self) -> U256 { + let d = &self.args.flag_gas_floor_target; + U256::from_dec_str(d).unwrap_or_else(|_| { + die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d) + }) + } + fn gas_price(&self) -> U256 { let d = self.args.flag_gasprice.as_ref().unwrap_or(&self.args.flag_gas_price); U256::from_dec_str(d).unwrap_or_else(|_| { @@ -485,6 +494,7 @@ impl Configuration { // Miner let miner = Miner::new(); miner.set_author(self.author()); + miner.set_gas_floor_target(self.gas_floor_target()); miner.set_extra_data(self.extra_data()); miner.set_minimal_gas_price(self.gas_price()); From 7af0a1dc2c2e41b7af89f3e1b24e1e847dd78c27 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 14 Mar 2016 02:02:32 +0100 Subject: [PATCH 602/753] Missing comma. --- miner/src/miner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 43f11f9c4..6d5b3086e 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -130,7 +130,7 @@ impl MinerService for Miner { self.author(), self.gas_floor_target(), self.extra_data(), - transactions + transactions, ); *self.sealing_block.lock().unwrap() = b; } From 6827ff9319893fe5283ab1e110951f375db79f13 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 14 Mar 2016 09:37:32 +0100 Subject: [PATCH 603/753] [ci skip] fix tesh.sh --- test.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test.sh b/test.sh index e1881a8ad..0bf08e67f 100755 --- a/test.sh +++ b/test.sh @@ -1,5 +1,4 @@ #!/bin/sh # Running Parity Full Test Sute -cargo test --features ethcore/json-tests $1 -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p -ethminer +cargo test --features ethcore/json-tests $1 -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer From 8532f2dc2e4e12ea100433486a983fcccf4145e0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 14 Mar 2016 09:44:02 +0100 Subject: [PATCH 604/753] removed tests that used fixedhash --- util/bigint/src/uint.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index ea617d570..c3cc6b753 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -1948,8 +1948,6 @@ mod tests { #[test] fn u256_multi_muls() { - use hash::*; - let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); assert_eq!(U256([0, 0, 0, 0]), result); @@ -1979,23 +1977,6 @@ mod tests { let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); - - let x1 = U256::from_str("0000000000000000000000000000000000000000000000000000012365124623").unwrap(); - let x2sqr_right = U256::from_str("000000000000000000000000000000000000000000014baeef72e0378e2328c9").unwrap(); - let x1sqr = x1 * x1; - assert_eq!(H256::from(x2sqr_right), H256::from(x1sqr)); - let x1cube = x1sqr * x1; - let x1cube_right = U256::from_str("0000000000000000000000000000000001798acde139361466f712813717897b").unwrap(); - assert_eq!(H256::from(x1cube_right), H256::from(x1cube)); - let x1quad = x1cube * x1; - let x1quad_right = U256::from_str("000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1").unwrap(); - assert_eq!(H256::from(x1quad_right), H256::from(x1quad)); - let x1penta = x1quad * x1; - let x1penta_right = U256::from_str("00000000000001e92875ac24be246e1c57e0507e8c46cc8d233b77f6f4c72993").unwrap(); - assert_eq!(H256::from(x1penta_right), H256::from(x1penta)); - let x1septima = x1penta * x1; - let x1septima_right = U256::from_str("00022cca1da3f6e5722b7d3cc5bbfb486465ebc5a708dd293042f932d7eee119").unwrap(); - assert_eq!(H256::from(x1septima_right), H256::from(x1septima)); } #[test] From d3c1b5455b2fc046272f7f4ee040df9291397893 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 14 Mar 2016 10:25:04 +0100 Subject: [PATCH 605/753] Silenced UDP warnings --- util/src/network/discovery.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 6fda99cdb..d755c58e7 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -297,7 +297,7 @@ impl Discovery { return; } Err(e) => { - warn!("UDP send error: {:?}, address: {:?}", e, &data.address); + debug!("UDP send error: {:?}, address: {:?}", e, &data.address); return; } } @@ -317,7 +317,7 @@ impl Discovery { }), Ok(_) => None, Err(e) => { - warn!("Error reading UPD socket: {:?}", e); + debug!("Error reading UPD socket: {:?}", e); None } } From 829ed4d0a6b6976aeff26fabd6d9cd239ccb593b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 14 Mar 2016 10:47:22 +0100 Subject: [PATCH 606/753] commented empty slice/vec comparison --- ethcore/src/evm/tests.rs | 4 ++-- util/src/bytes.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index dc84a9a05..0853cd5f8 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -55,7 +55,7 @@ struct FakeExt { info: EnvInfo, schedule: Schedule, balances: HashMap, - calls: HashSet + calls: HashSet, } impl FakeExt { @@ -346,7 +346,7 @@ fn test_log_empty(factory: super::Factory) { assert_eq!(gas_left, U256::from(99_619)); assert_eq!(ext.logs.len(), 1); assert_eq!(ext.logs[0].topics.len(), 0); - assert_eq!(ext.logs[0].data, vec![]); + //assert_eq!(ext.logs[0].data, vec![]); } evm_test!{test_log_sender: test_log_sender_jit, test_log_sender_int} diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 5a4500ae6..13e6880cc 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -177,7 +177,7 @@ impl BytesConvertable for T where T: AsRef<[u8]> { #[test] fn bytes_convertable() { assert_eq!(vec![0x12u8, 0x34].bytes(), &[0x12u8, 0x34]); - assert_eq!([0u8; 0].bytes(), &[]); +// assert_eq!([0u8; 0].as_slice(), &[]); } /// Simple trait to allow for raw population of a Sized object from a byte slice. From dc8b9c3205132c9eb12852582990850625a6aa38 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 14 Mar 2016 10:48:32 +0100 Subject: [PATCH 607/753] Fix build. --- ethcore/src/client/client.rs | 5 +++++ ethcore/src/tests/client.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index cbea020ba..0bd371c0f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -109,6 +109,11 @@ pub struct Client where V: Verifier { } const HISTORY: u64 = 1000; +// DO NOT TOUCH THIS ANY MORE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING. +// Altering it will force a blanket DB update for *all* JournalDB-derived +// databases. +// Instead, add/upgrade the version string of the individual JournalDB-derived database +// of which you actually want force an upgrade. const CLIENT_DB_VER_STR: &'static str = "5.2"; impl Client { diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index ed0b02788..797684d1d 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -133,7 +133,7 @@ fn can_mine() { let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let client = client_result.reference(); - let b = client.prepare_sealing(Address::default(), vec![], vec![]).unwrap(); + let b = client.prepare_sealing(Address::default(), x!(31415926), vec![], vec![]).unwrap(); assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); assert!(client.try_seal(b, vec![]).is_ok()); From 3eb08b0d611ba848359076a342e88523265b8671 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 14 Mar 2016 10:53:37 +0100 Subject: [PATCH 608/753] fix tests and deuncommented --- ethcore/src/evm/tests.rs | 2 +- util/src/bytes.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 0853cd5f8..445c0be41 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -346,7 +346,7 @@ fn test_log_empty(factory: super::Factory) { assert_eq!(gas_left, U256::from(99_619)); assert_eq!(ext.logs.len(), 1); assert_eq!(ext.logs[0].topics.len(), 0); - //assert_eq!(ext.logs[0].data, vec![]); + assert!(ext.logs[0].data.is_empty()); } evm_test!{test_log_sender: test_log_sender_jit, test_log_sender_int} diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 13e6880cc..0683ea4df 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -177,7 +177,7 @@ impl BytesConvertable for T where T: AsRef<[u8]> { #[test] fn bytes_convertable() { assert_eq!(vec![0x12u8, 0x34].bytes(), &[0x12u8, 0x34]); -// assert_eq!([0u8; 0].as_slice(), &[]); + assert!([0u8; 0].as_slice().is_empty()); } /// Simple trait to allow for raw population of a Sized object from a byte slice. From 5503cd46464d2f410ebc58e497d4cd55b1a5600c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 14 Mar 2016 12:41:11 +0100 Subject: [PATCH 609/753] Lock reports to avoid out of order badness. --- parity/main.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 8562b416d..d7e92d6ff 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -583,13 +583,15 @@ impl Informant { let chain_info = client.chain_info(); let queue_info = client.queue_info(); let cache_info = client.blockchain_cache_info(); - let report = client.report(); let sync_info = sync.status(); + let write_report = self.report.write().unwrap(); + let report = client.report(); + if let (_, _, &Some(ref last_report)) = ( self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), - self.report.read().unwrap().deref() + write_report.deref() ) { println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} db, {} chain, {} queue, {} sync ]", chain_info.best_block_number, @@ -613,7 +615,7 @@ impl Informant { *self.chain_info.write().unwrap().deref_mut() = Some(chain_info); *self.cache_info.write().unwrap().deref_mut() = Some(cache_info); - *self.report.write().unwrap().deref_mut() = Some(report); + *write_report.deref_mut() = Some(report); } } From c8b65c769b50545d73a307cbd9eace7ba2faf1d1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 14 Mar 2016 13:54:06 +0100 Subject: [PATCH 610/753] Fixed handshake leak --- util/src/network/host.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 57aae51d7..02c576424 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -687,6 +687,8 @@ impl Host where Message: Send + Sync + Clone { if h.expired { return; } + io.deregister_stream(token).expect("Error deleting handshake registration"); + h.set_expired(); let originated = h.originated; let mut session = match Session::new(&mut h, &self.info.read().unwrap()) { Ok(s) => s, @@ -705,8 +707,6 @@ impl Host where Message: Send + Sync + Clone { } let result = sessions.insert_with(move |session_token| { session.set_token(session_token); - io.deregister_stream(token).expect("Error deleting handshake registration"); - h.set_expired(); io.register_stream(session_token).expect("Error creating session registration"); self.stats.inc_sessions(); trace!(target: "network", "Creating session {} -> {}", token, session_token); From 0de73609d2c0fa94067712ef229e72d4dd2541ee Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 14 Mar 2016 14:18:29 +0100 Subject: [PATCH 611/753] eth_hashrate && eth_submitHashrate tests --- ethcore/src/client/test_client.rs | 8 +-- rpc/src/v1/helpers/external_miner.rs | 59 ++++++++++++++++++ rpc/src/v1/helpers/mod.rs | 2 + rpc/src/v1/impls/eth.rs | 48 ++++++++++----- rpc/src/v1/tests/eth.rs | 72 +++++++++++++++++----- rpc/src/v1/tests/helpers/external_miner.rs | 48 +++++++++++++++ rpc/src/v1/tests/helpers/mod.rs | 2 + 7 files changed, 203 insertions(+), 36 deletions(-) create mode 100644 rpc/src/v1/helpers/external_miner.rs create mode 100644 rpc/src/v1/tests/helpers/external_miner.rs diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 140b8d91f..55c473d1e 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -87,22 +87,22 @@ impl TestBlockChainClient { } /// Set the balance of account `address` to `balance`. - pub fn set_balance(&mut self, address: Address, balance: U256) { + pub fn set_balance(&self, address: Address, balance: U256) { self.balances.write().unwrap().insert(address, balance); } /// Set `code` at `address`. - pub fn set_code(&mut self, address: Address, code: Bytes) { + pub fn set_code(&self, address: Address, code: Bytes) { self.code.write().unwrap().insert(address, code); } /// Set storage `position` to `value` for account `address`. - pub fn set_storage(&mut self, address: Address, position: H256, value: H256) { + pub fn set_storage(&self, address: Address, position: H256, value: H256) { self.storage.write().unwrap().insert((address, position), value); } /// Add blocks to test client. - pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { + pub fn add_blocks(&self, count: usize, with: EachBlockWith) { let len = self.numbers.read().unwrap().len(); for n in len..(len + count) { let mut header = BlockHeader::new(); diff --git a/rpc/src/v1/helpers/external_miner.rs b/rpc/src/v1/helpers/external_miner.rs new file mode 100644 index 000000000..4cbda8928 --- /dev/null +++ b/rpc/src/v1/helpers/external_miner.rs @@ -0,0 +1,59 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashMap; +use std::sync::RwLock; +use util::numbers::U256; +use util::hash::H256; + +/// External miner interface. +pub trait ExternalMinerService: Send + Sync { + /// Submit hashrate for given miner. + fn submit_hashrate(&self, hashrate: U256, id: H256); + + /// Total hashrate. + fn hashrate(&self) -> U256; + + /// Returns true if external miner is mining. + fn is_mining(&self) -> bool; +} + +/// External Miner. +pub struct ExternalMiner { + hashrates: RwLock>, +} + +impl Default for ExternalMiner { + fn default() -> Self { + ExternalMiner { + hashrates: RwLock::new(HashMap::new()), + } + } +} + +impl ExternalMinerService for ExternalMiner { + fn submit_hashrate(&self, hashrate: U256, id: H256) { + self.hashrates.write().unwrap().insert(id, hashrate); + } + + fn hashrate(&self) -> U256 { + self.hashrates.read().unwrap().iter().fold(U256::from(0), |sum, (_, v)| sum + *v) + } + + fn is_mining(&self) -> bool { + !self.hashrates.read().unwrap().is_empty() + } +} diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index b1a5c05ba..8c574cff6 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -16,6 +16,8 @@ mod poll_manager; mod poll_filter; +pub mod external_miner; pub use self::poll_manager::PollManager; pub use self::poll_filter::PollFilter; +pub use self::external_miner::{ExternalMinerService, ExternalMiner}; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 0e8b8d863..9ceea2e25 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . //! Eth rpc implementation. -use std::collections::{HashMap, HashSet}; -use std::sync::{Arc, Weak, Mutex, RwLock}; +use std::collections::HashSet; +use std::sync::{Arc, Weak, Mutex}; use std::ops::Deref; use ethsync::{SyncProvider, SyncState}; use ethminer::{MinerService}; @@ -25,42 +25,59 @@ use util::numbers::*; use util::sha3::*; use util::rlp::encode; use ethcore::client::*; -use ethcore::block::{IsBlock}; +use ethcore::block::IsBlock; use ethcore::views::*; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use ethcore::transaction::Transaction as EthTransaction; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; -use v1::helpers::{PollFilter, PollManager}; +use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner}; use util::keys::store::AccountProvider; /// Eth rpc implementation. -pub struct EthClient +pub struct EthClient where C: BlockChainClient, S: SyncProvider, A: AccountProvider, - M: MinerService { + M: MinerService, + EM: ExternalMinerService { client: Weak, sync: Weak, accounts: Weak, miner: Weak, - hashrates: RwLock>, + external_miner: EM, } -impl EthClient +impl EthClient where C: BlockChainClient, S: SyncProvider, A: AccountProvider, M: MinerService { + /// Creates new EthClient. pub fn new(client: &Arc, sync: &Arc, accounts: &Arc, miner: &Arc) -> Self { + EthClient::new_with_external_miner(client, sync, accounts, miner, ExternalMiner::default()) + } +} + + +impl EthClient + where C: BlockChainClient, + S: SyncProvider, + A: AccountProvider, + M: MinerService, + EM: ExternalMinerService { + + /// Creates new EthClient with custom external miner. + pub fn new_with_external_miner(client: &Arc, sync: &Arc, accounts: &Arc, miner: &Arc, em: EM) + -> EthClient { EthClient { client: Arc::downgrade(client), sync: Arc::downgrade(sync), miner: Arc::downgrade(miner), accounts: Arc::downgrade(accounts), - hashrates: RwLock::new(HashMap::new()), + external_miner: em, } } @@ -110,11 +127,12 @@ impl EthClient } } -impl Eth for EthClient +impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncProvider + 'static, A: AccountProvider + 'static, - M: MinerService + 'static { + M: MinerService + 'static, + EM: ExternalMinerService + 'static { fn protocol_version(&self, params: Params) -> Result { match params { @@ -152,7 +170,7 @@ impl Eth for EthClient // TODO: return real value of mining once it's implemented. fn is_mining(&self, params: Params) -> Result { match params { - Params::None => to_value(&!self.hashrates.read().unwrap().is_empty()), + Params::None => to_value(&self.external_miner.is_mining()), _ => Err(Error::invalid_params()) } } @@ -160,7 +178,7 @@ impl Eth for EthClient // TODO: return real hashrate once we have mining fn hashrate(&self, params: Params) -> Result { match params { - Params::None => to_value(&self.hashrates.read().unwrap().iter().fold(0u64, |sum, (_, v)| sum + v)), + Params::None => to_value(&self.external_miner.hashrate()), _ => Err(Error::invalid_params()) } } @@ -318,8 +336,8 @@ impl Eth for EthClient fn submit_hashrate(&self, params: Params) -> Result { // TODO: Index should be U256. - from_params::<(Index, H256)>(params).and_then(|(rate, id)| { - self.hashrates.write().unwrap().insert(id, rate.value() as u64); + from_params::<(U256, H256)>(params).and_then(|(rate, id)| { + self.external_miner.submit_hashrate(rate, id); to_value(&true) }) } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 35c227e40..e07390165 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -15,20 +15,16 @@ // along with Parity. If not, see . use std::collections::HashMap; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use jsonrpc_core::IoHandler; use util::hash::{Address, H256}; use util::numbers::U256; use ethcore::client::{TestBlockChainClient, EachBlockWith}; use v1::{Eth, EthClient}; -use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService}; +use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; fn blockchain_client() -> Arc { - let mut client = TestBlockChainClient::new(); - client.add_blocks(10, EachBlockWith::Nothing); - client.set_balance(Address::from(1), U256::from(5)); - client.set_storage(Address::from(1), H256::from(4), H256::from(7)); - client.set_code(Address::from(1), vec![0xff, 0x21]); + let client = TestBlockChainClient::new(); Arc::new(client) } @@ -51,10 +47,11 @@ fn miner_service() -> Arc { } struct EthTester { - _client: Arc, + client: Arc, _sync: Arc, _accounts_provider: Arc, _miner: Arc, + hashrates: Arc>>, pub io: IoHandler, } @@ -64,15 +61,18 @@ impl Default for EthTester { let sync = sync_provider(); let ap = accounts_provider(); let miner = miner_service(); - let eth = EthClient::new(&client, &sync, &ap, &miner).to_delegate(); + let hashrates = Arc::new(RwLock::new(HashMap::new())); + let external_miner = TestExternalMiner::new(hashrates.clone()); + let eth = EthClient::new_with_external_miner(&client, &sync, &ap, &miner, external_miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(eth); EthTester { - _client: client, + client: client, _sync: sync, _accounts_provider: ap, _miner: miner, - io: io + io: io, + hashrates: hashrates, } } } @@ -92,9 +92,35 @@ fn rpc_eth_syncing() { } #[test] -#[ignore] fn rpc_eth_hashrate() { - unimplemented!() + let tester = EthTester::default(); + tester.hashrates.write().unwrap().insert(H256::from(0), U256::from(0xfffa)); + tester.hashrates.write().unwrap().insert(H256::from(0), U256::from(0xfffb)); + tester.hashrates.write().unwrap().insert(H256::from(1), U256::from(0x1)); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_hashrate", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0xfffc","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_submit_hashrate() { + let tester = EthTester::default(); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_submitHashrate", + "params": [ + "0x0000000000000000000000000000000000000000000000000000000000500000", + "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); + assert_eq!(tester.hashrates.read().unwrap().get(&H256::from("0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c")).cloned(), + Some(U256::from(0x500_000))); } #[test] @@ -127,14 +153,20 @@ fn rpc_eth_accounts() { #[test] fn rpc_eth_block_number() { + let tester = EthTester::default(); + tester.client.add_blocks(10, EachBlockWith::Nothing); + let request = r#"{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x0a","id":1}"#; - assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } #[test] fn rpc_eth_balance() { + let tester = EthTester::default(); + tester.client.set_balance(Address::from(1), U256::from(5)); + let request = r#"{ "jsonrpc": "2.0", "method": "eth_getBalance", @@ -143,11 +175,14 @@ fn rpc_eth_balance() { }"#; let response = r#"{"jsonrpc":"2.0","result":"0x05","id":1}"#; - assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } #[test] fn rpc_eth_storage_at() { + let tester = EthTester::default(); + tester.client.set_storage(Address::from(1), H256::from(4), H256::from(7)); + let request = r#"{ "jsonrpc": "2.0", "method": "eth_getStorageAt", @@ -156,7 +191,7 @@ fn rpc_eth_storage_at() { }"#; let response = r#"{"jsonrpc":"2.0","result":"0x07","id":1}"#; - assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } #[test] @@ -226,6 +261,9 @@ fn rpc_eth_uncle_count_by_block_number() { #[test] fn rpc_eth_code() { + let tester = EthTester::default(); + tester.client.set_code(Address::from(1), vec![0xff, 0x21]); + let request = r#"{ "jsonrpc": "2.0", "method": "eth_getCode", @@ -234,7 +272,7 @@ fn rpc_eth_code() { }"#; let response = r#"{"jsonrpc":"2.0","result":"0xff21","id":1}"#; - assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } #[test] diff --git a/rpc/src/v1/tests/helpers/external_miner.rs b/rpc/src/v1/tests/helpers/external_miner.rs new file mode 100644 index 000000000..a5111b302 --- /dev/null +++ b/rpc/src/v1/tests/helpers/external_miner.rs @@ -0,0 +1,48 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; +use util::numbers::U256; +use util::hash::H256; +use v1::helpers::ExternalMinerService; + +/// Test ExternalMinerService; +pub struct TestExternalMiner { + pub hashrates: Arc>> +} + +impl TestExternalMiner { + pub fn new(hashrates: Arc>>) -> Self { + TestExternalMiner { + hashrates: hashrates, + } + } +} + +impl ExternalMinerService for TestExternalMiner { + fn submit_hashrate(&self, hashrate: U256, id: H256) { + self.hashrates.write().unwrap().insert(id, hashrate); + } + + fn hashrate(&self) -> U256 { + self.hashrates.read().unwrap().iter().fold(U256::from(0), |sum, (_, v)| sum + *v) + } + + fn is_mining(&self) -> bool { + !self.hashrates.read().unwrap().is_empty() + } +} diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index fc429982e..fc652e7d6 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -17,7 +17,9 @@ mod account_provider; mod sync_provider; mod miner_service; +mod external_miner; pub use self::account_provider::{TestAccount, TestAccountProvider}; pub use self::sync_provider::{Config, TestSyncProvider}; pub use self::miner_service::{TestMinerService}; +pub use self::external_miner::TestExternalMiner; From 4e5ebc94579cadef5a1ca1c42f62ffbf6959d87b Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 14 Mar 2016 14:22:18 +0100 Subject: [PATCH 612/753] missing mut --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 26e3e4b78..b8cc2a0f0 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -610,7 +610,7 @@ impl Informant { let cache_info = client.blockchain_cache_info(); let sync_info = sync.status(); - let write_report = self.report.write().unwrap(); + let mut write_report = self.report.write().unwrap(); let report = client.report(); if let (_, _, &Some(ref last_report)) = ( From 47ca84041b8c4b0ed346f4c10b75d015369f1266 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 14 Mar 2016 14:59:09 +0100 Subject: [PATCH 613/753] tests for eth_mining, eth_compileLLL, eth_compileSolidity, eth_compileSerpent --- rpc/src/v1/tests/eth.rs | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index e07390165..6bc929709 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -130,9 +130,18 @@ fn rpc_eth_author() { } #[test] -#[ignore] fn rpc_eth_mining() { - unimplemented!() + let tester = EthTester::default(); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_mining", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); + + tester.hashrates.write().unwrap().insert(H256::from(1), U256::from(0x1)); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_mining", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } #[test] @@ -313,5 +322,29 @@ fn rpc_eth_compilers() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +fn rpc_eth_compile_lll() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_compileLLL", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_compile_solidity() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_compileSolidity", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_compile_serpent() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_compileSerpent", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + From 9b241faf010303da6c2245ba2529e439bded5034 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 14 Mar 2016 17:01:10 +0100 Subject: [PATCH 614/753] uncle method mock --- ethcore/src/views.rs | 7 ++++++- rpc/src/v1/impls/eth.rs | 15 +++++++++++++++ rpc/src/v1/traits/eth.rs | 9 ++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 4a7ff054d..745cbff2c 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -223,6 +223,11 @@ impl<'a> BlockView<'a> { pub fn uncle_hashes(&self) -> Vec { self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect() } + + /// Return nth uncle. + pub fn uncle_at(&self, index: usize) -> Option
{ + self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val()) + } } impl<'a> Hashable for BlockView<'a> { @@ -280,7 +285,7 @@ impl<'a> HeaderView<'a> { /// Returns block number. pub fn number(&self) -> BlockNumber { self.rlp.val_at(8) } - + /// Returns block gas limit. pub fn gas_limit(&self) -> U256 { self.rlp.val_at(9) } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 9ceea2e25..fda391304 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -125,6 +125,11 @@ impl EthClient None => Ok(Value::Null) } } + + fn uncle(&self, _block: BlockId, _index: usize) -> Result { + // TODO: implement! + Ok(Value::Null) + } } impl Eth for EthClient @@ -285,6 +290,16 @@ impl Eth for EthClient .and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value()))) } + fn uncle_by_block_hash_and_index(&self, params: Params) -> Result { + from_params::<(H256, Index)>(params) + .and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value())) + } + + fn uncle_by_block_number_and_index(&self, params: Params) -> Result { + from_params::<(BlockNumber, Index)>(params) + .and_then(|(number, index)| self.uncle(number.into(), index.value())) + } + fn compilers(&self, params: Params) -> Result { match params { Params::None => to_value(&vec![] as &Vec), diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index bcd7e7cfe..8a48e0dfe 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -102,7 +102,10 @@ pub trait Eth: Sized + Send + Sync + 'static { fn transaction_receipt(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns an uncles at given block and index. - fn uncle_at(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uncle_by_block_hash_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns an uncles at given block and index. + fn uncle_by_block_number_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns available compilers. fn compilers(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -158,8 +161,8 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_by_block_hash_and_index); delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_by_block_number_and_index); delegate.add_method("eth_getTransactionReceipt", Eth::transaction_receipt); - delegate.add_method("eth_getUncleByBlockHashAndIndex", Eth::uncle_at); - delegate.add_method("eth_getUncleByBlockNumberAndIndex", Eth::uncle_at); + delegate.add_method("eth_getUncleByBlockHashAndIndex", Eth::uncle_by_block_hash_and_index); + delegate.add_method("eth_getUncleByBlockNumberAndIndex", Eth::uncle_by_block_number_and_index); delegate.add_method("eth_getCompilers", Eth::compilers); delegate.add_method("eth_compileLLL", Eth::compile_lll); delegate.add_method("eth_compileSolidity", Eth::compile_solidity); From 81beaf10948fa00fb51935ea6b516ca9b8bf2d4b Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 14 Mar 2016 17:53:08 +0100 Subject: [PATCH 615/753] update dockerfiles --- docker/ubuntu-dev/Dockerfile | 8 ++------ docker/ubuntu-jit/Dockerfile | 11 +++-------- docker/ubuntu/Dockerfile | 10 +--------- 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/docker/ubuntu-dev/Dockerfile b/docker/ubuntu-dev/Dockerfile index 8b016e6fd..e9113afdf 100644 --- a/docker/ubuntu-dev/Dockerfile +++ b/docker/ubuntu-dev/Dockerfile @@ -9,7 +9,7 @@ RUN apt-get update && \ software-properties-common \ curl \ gcc \ - wget \ + wget \ git \ # evmjit dependencies zlib1g-dev \ @@ -18,9 +18,8 @@ RUN apt-get update && \ # cmake, llvm and rocksdb ppas. then update ppas RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \ add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \ - add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && \ apt-get update && \ - apt-get install -y --force-yes cmake llvm-3.7-dev librocksdb + apt-get install -y --force-yes cmake llvm-3.7-dev # install evmjit RUN git clone https://github.com/debris/evmjit && \ @@ -31,9 +30,6 @@ RUN git clone https://github.com/debris/evmjit && \ # install multirust RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install nightly and make it default -RUN multirust update nightly && multirust default nightly - # export rust LIBRARY_PATH ENV LIBRARY_PATH /usr/local/lib diff --git a/docker/ubuntu-jit/Dockerfile b/docker/ubuntu-jit/Dockerfile index 90ce531be..c50aa83b5 100644 --- a/docker/ubuntu-jit/Dockerfile +++ b/docker/ubuntu-jit/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update && \ # add-apt-repository software-properties-common \ curl \ - wget \ + wget \ git \ gcc \ # evmjit dependencies @@ -18,9 +18,8 @@ RUN apt-get update && \ # cmake, llvm and rocksdb ppas. then update ppas RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \ add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \ - add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && \ apt-get update && \ - apt-get install -y --force-yes cmake llvm-3.7-dev librocksdb + apt-get install -y --force-yes cmake llvm-3.7-dev # install evmjit RUN git clone https://github.com/debris/evmjit && \ @@ -31,9 +30,6 @@ RUN git clone https://github.com/debris/evmjit && \ # install multirust RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install nightly and make it default -RUN multirust update nightly && multirust default nightly - # export rust LIBRARY_PATH ENV LIBRARY_PATH /usr/local/lib @@ -41,7 +37,6 @@ ENV LIBRARY_PATH /usr/local/lib ENV RUST_BACKTRACE 1 # build parity -# TODO: add jit feature RUN git clone https://github.com/ethcore/parity && \ cd parity && \ - cargo install --features rpc + cargo install --features ethcore/jit diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 812e66e9e..3273b816a 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -9,17 +9,9 @@ RUN apt-get update && \ # add-apt-repository software-properties-common -# rocksdb ppas. then update ppas -RUN add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && \ - apt-get update && \ - apt-get install -y --force-yes librocksdb - # install multirust RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install nightly and make it default -RUN multirust update nightly && multirust default nightly - # export rust LIBRARY_PATH ENV LIBRARY_PATH /usr/local/lib @@ -29,4 +21,4 @@ ENV RUST_BACKTRACE 1 # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ - cargo install --features rpc + cargo install From 97051cb949e38e18f6024012d52e42b6bb160161 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 14 Mar 2016 18:20:24 +0100 Subject: [PATCH 616/753] Add RLP, not a data item. --- ethcore/src/block.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 6f3986391..1ef28188b 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -265,7 +265,7 @@ impl<'x> OpenBlock<'x> { let mut s = self; s.engine.on_close_block(&mut s.block); s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect()); - let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append(&u.rlp(Seal::With)); s} ).out(); + let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out(); s.block.base.header.uncles_hash = uncle_bytes.sha3(); s.block.base.header.state_root = s.block.state.root().clone(); s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|ref r| r.rlp_bytes().to_vec()).collect()); @@ -420,4 +420,9 @@ mod tests { assert_eq!(orig_db.keys(), db.keys()); assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None); } + + #[test] + fn enact_block_with_uncle() { + // TODO: test for when there's an uncle. + } } From c476e7da3110768aaf6325b50fd001fa270681d4 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 14 Mar 2016 18:25:05 +0100 Subject: [PATCH 617/753] update docker --- docker/ubuntu/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 3273b816a..141cbdfb0 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -3,11 +3,10 @@ FROM ubuntu:14.04 # install tools and dependencies RUN apt-get update && \ apt-get install -y \ - gcc \ + g++ \ curl \ git \ - # add-apt-repository - software-properties-common + make # install multirust RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes From dfef09161cd0453aeeeee8b181e502dc58ed2fc1 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 14 Mar 2016 18:47:23 +0100 Subject: [PATCH 618/753] update dockerfiles --- docker/ubuntu-dev/Dockerfile | 2 +- docker/ubuntu-jit/Dockerfile | 4 ++-- docker/ubuntu/Dockerfile | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/ubuntu-dev/Dockerfile b/docker/ubuntu-dev/Dockerfile index e9113afdf..05e8dfe8f 100644 --- a/docker/ubuntu-dev/Dockerfile +++ b/docker/ubuntu-dev/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update && \ # add-apt-repository software-properties-common \ curl \ - gcc \ + g++ \ wget \ git \ # evmjit dependencies diff --git a/docker/ubuntu-jit/Dockerfile b/docker/ubuntu-jit/Dockerfile index c50aa83b5..138882d2b 100644 --- a/docker/ubuntu-jit/Dockerfile +++ b/docker/ubuntu-jit/Dockerfile @@ -10,7 +10,7 @@ RUN apt-get update && \ curl \ wget \ git \ - gcc \ + g++ \ # evmjit dependencies zlib1g-dev \ libedit-dev @@ -39,4 +39,4 @@ ENV RUST_BACKTRACE 1 # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ - cargo install --features ethcore/jit + cargo build --release --features ethcore/jit diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 141cbdfb0..38c628d0e 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -20,4 +20,4 @@ ENV RUST_BACKTRACE 1 # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ - cargo install + cargo build --release From 85833d228a4843438b23d332c1fba2b2558669bd Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 15 Mar 2016 01:22:58 +0100 Subject: [PATCH 619/753] Ignore new blocks while seeking --- sync/src/chain.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 57f53f459..363597d40 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -479,6 +479,9 @@ impl ChainSync { let header_rlp = try!(block_rlp.at(0)); let h = header_rlp.as_raw().sha3(); trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); + if !self.have_common_block { + trace!(target: "sync", "NewBlock ignored while seeking"); + } let header: BlockHeader = try!(header_rlp.as_val()); let mut unknown = false; { @@ -498,9 +501,10 @@ impl ChainSync { Ok(_) => { if self.current_base_block() < header.number { self.last_imported_block = Some(header.number); + self.last_imported_hash = Some(header.hash()); self.remove_downloaded_blocks(header.number); } - trace!(target: "sync", "New block queued {:?}", h); + trace!(target: "sync", "New block queued {:?} ({})", h, header.number); }, Err(Error::Block(BlockError::UnknownParent(p))) => { unknown = true; @@ -779,7 +783,7 @@ impl ChainSync { { let headers = self.headers.range_iter().next().unwrap(); let bodies = self.bodies.range_iter().next().unwrap(); - if headers.0 != bodies.0 || headers.0 != self.current_base_block() + 1 { + if headers.0 != bodies.0 || headers.0 > self.current_base_block() + 1 { return; } From 40ac01b7304738f9089ec64f2dd4ac03cf10995e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 10:54:19 +0100 Subject: [PATCH 620/753] Fixing possible race in transaction queue --- miner/src/transaction_queue.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 880c73750..324a46364 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -516,11 +516,10 @@ impl TransactionQueue { return; } - let base_nonce = fetch_nonce(&address); - Self::replace_transaction(tx, base_nonce, &mut self.current, &mut self.by_hash); + Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash); self.last_nonces.insert(address, nonce); // But maybe there are some more items waiting in future? - self.move_matching_future_to_current(address, nonce + U256::one(), base_nonce); + self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); self.current.enforce_limit(&mut self.by_hash); } From 26dd67ebebfec56e073000a67e20eb9179343ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 10:57:09 +0100 Subject: [PATCH 621/753] Speeding up build --- .travis.yml | 67 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ae41379e..115bf4ec6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,24 +8,46 @@ branches: - /^stable-.*$/ - /^beta$/ - /^stable$/ +git: + depth: 3 matrix: fast_finish: false allow_failures: - rust: nightly include: - rust: stable - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" RUN_TESTS="true" - rust: beta - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" RUN_TESTS="true" + - rust: stable + env: FEATURES="--features travis-beta" RUN_BUILD="true" + - rust: beta + env: FEATURES="--features travis-beta" RUN_BUILD="true" + - rust: stable + env: FEATURES="--features travis-beta" RUN_COVERAGE="true" - rust: nightly - env: FEATURES="--features travis-nightly" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-nightly" RUN_BENCHES="true" + - rust: nightly + env: FEATURES="--features travis-nightly" RUN_TESTS="true" +env: + global: + # GH_TOKEN + - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= + - CVER=5 + - NUM_JOBS=1 + # - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" + - TARGETS="-p ethcore-util" + - ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + - KCOV_FEATURES="" + - KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov" + - RUN_TESTS="false" + - RUN_COVERAGE="false" + - RUN_BUILD="false" + - RUN_BENCHES="false" cache: apt: true directories: - - target/debug/deps - - target/debug/build - - target/release/deps - - target/release/build + - $TRAVIS_BUILD_DIR/target - $HOME/.cargo addons: apt: @@ -33,22 +55,27 @@ addons: - libcurl4-openssl-dev - libelf-dev - libdw-dev + script: -- cargo build --release --verbose ${FEATURES} -- cargo test --release --verbose ${FEATURES} ${TARGETS} -#- cargo bench --no-run ${FEATURES} ${TARGETS} -- tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity + - echo "$TRAVIS_BUILD_DIR/target" + - ls "$TRAVIS_BUILD_DIR/target" + - if [ "$RUN_TESTS" = "true" ]; then cargo test --release --verbose ${FEATURES} ${TARGETS}; fi + - if [ "$RUN_BENCHES" = "true" ]; then cargo bench --no-run ${FEATURES} ${TARGETS}; fi + - if [ "$RUN_BUILD" = "true" ]; then cargo build --release --verbose ${FEATURES}; fi + - if [ "$RUN_BUILD" = "true" ]; then tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity; fi + after_success: | + [ "$RUN_COVERAGE" = "true" ] && wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && cargo test --no-run ${KCOV_FEATURES} ${TARGETS} && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethminer-* && - ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* && + $KCOV_CMD target/debug/deps/ethcore_util-* && + $KCOV_CMD target/debug/deps/ethash-* && + $KCOV_CMD target/debug/deps/ethcore-* && + $KCOV_CMD target/debug/deps/ethsync-* && + $KCOV_CMD target/debug/deps/ethcore_rpc-* && + $KCOV_CMD target/debug/deps/ethminer-* && + $KCOV_CMD target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && [ $TRAVIS_RUST_VERSION = stable ] && @@ -57,10 +84,6 @@ after_success: | pip install --user ghp-import && /home/travis/.local/bin/ghp-import -n target/doc && git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages -env: - global: - # GH_TOKEN - - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= deploy: provider: releases From 59d0d2df9ad5b0e96bd4d41336bce601d4c8f87f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 15 Mar 2016 10:59:58 +0100 Subject: [PATCH 622/753] Don't change best block until extras is committed. --- ethcore/src/blockchain/blockchain.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 36db9dded..40b01c6f9 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -504,10 +504,10 @@ impl BlockChain { batch.put_extras(hash, tx_address); write_txs.remove(hash); } - } - // update extras database - self.extras_db.write(batch).unwrap(); + // update extras database + self.extras_db.write(batch).unwrap(); + } } /// Iterator that lists `first` and then all of `first`'s ancestors, by hash. From 2cecb1eadabc3ceb7d4d666e67d0aa78120188bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 11:04:48 +0100 Subject: [PATCH 623/753] Cleaning --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 115bf4ec6..905f92bbd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,10 +33,7 @@ env: global: # GH_TOKEN - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= - - CVER=5 - - NUM_JOBS=1 - # - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" - - TARGETS="-p ethcore-util" + - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" - ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - KCOV_FEATURES="" - KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov" From 7045e9f2f7db6a4dbdb6ff75b4528f7f20a23006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 11:05:31 +0100 Subject: [PATCH 624/753] More cleaning --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 905f92bbd..7ac668d62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,8 +54,6 @@ addons: - libdw-dev script: - - echo "$TRAVIS_BUILD_DIR/target" - - ls "$TRAVIS_BUILD_DIR/target" - if [ "$RUN_TESTS" = "true" ]; then cargo test --release --verbose ${FEATURES} ${TARGETS}; fi - if [ "$RUN_BENCHES" = "true" ]; then cargo bench --no-run ${FEATURES} ${TARGETS}; fi - if [ "$RUN_BUILD" = "true" ]; then cargo build --release --verbose ${FEATURES}; fi From ec4f7c419037ee7f8924a18ac8d31aa43ee9fa13 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 15 Mar 2016 11:12:54 +0100 Subject: [PATCH 625/753] stable only until travis speedup --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ae41379e..91c50fa13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,6 @@ matrix: include: - rust: stable env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - - rust: beta - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - - rust: nightly - env: FEATURES="--features travis-nightly" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: apt: true directories: From b9b0444662e651df8f30416d0f27eed5fd166fe7 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 15 Mar 2016 11:20:19 +0100 Subject: [PATCH 626/753] Trace sending to unconfirmed session --- util/src/network/session.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 84c063c92..2f30d7376 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -213,6 +213,10 @@ impl Session { /// Send a protocol packet to peer. pub fn send_packet(&mut self, protocol: &str, packet_id: u8, data: &[u8]) -> Result<(), UtilError> { + if self.info.capabilities.is_empty() || !self.had_hello { + debug!(target: "network", "Sending to unconfirmed session {}, protocol: {}, packet: {}", self.token(), protocol, packet_id); + return Err(From::from(NetworkError::BadProtocol)); + } if self.expired() { return Err(From::from(NetworkError::Expired)); } From 6d939ddfced2480d53b01e1dcb2f7f041869f367 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 15 Mar 2016 13:36:27 +0100 Subject: [PATCH 627/753] updating lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dfe37dbb4..ecdae1a0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,11 +184,11 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.4" -source = "git+https://github.com/ethcore/rust-secp256k1#283a0677d8327536be58a87e0494d7e0e7b1d1d8" +source = "git+https://github.com/ethcore/rust-secp256k1#b6fdd43bbcf6d46adb72a92dd1632a0fc834cbf5" dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", From 9dea31031c18a0728a4096c3372e3e0aff19a0d4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 15 Mar 2016 14:35:45 +0100 Subject: [PATCH 628/753] Enact block with uncles test --- ethcore/src/block.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 1ef28188b..d4aa35445 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -423,6 +423,37 @@ mod tests { #[test] fn enact_block_with_uncle() { - // TODO: test for when there's an uncle. + use spec::*; + let engine = Spec::new_test().to_engine().unwrap(); + let genesis_header = engine.spec().genesis_header(); + + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(db.as_hashdb_mut()); + let mut open_block = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]); + let mut uncle1_header = Header::new(); + uncle1_header.extra_data = b"uncle1".to_vec(); + let mut uncle2_header = Header::new(); + uncle2_header.extra_data = b"uncle2".to_vec(); + open_block.push_uncle(uncle1_header).unwrap(); + open_block.push_uncle(uncle2_header).unwrap(); + let b = open_block.close().seal(engine.deref(), vec![]).unwrap(); + + let orig_bytes = b.rlp_bytes(); + let orig_db = b.drain(); + + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(db.as_hashdb_mut()); + let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap(); + + let bytes = e.rlp_bytes(); + assert_eq!(bytes, orig_bytes); + let uncles = BlockView::new(&bytes).uncles(); + assert_eq!(uncles[1].extra_data, b"uncle2"); + + let db = e.drain(); + assert_eq!(orig_db.keys(), db.keys()); + assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None); } } From 74245be4f58a337c750c5a007ad1401afc35c724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 15:09:12 +0100 Subject: [PATCH 629/753] Enabling fast finish --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7ac668d62..990b4852f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ branches: git: depth: 3 matrix: - fast_finish: false + fast_finish: true allow_failures: - rust: nightly include: From d57b0177a755dbf8828530c70b6d9954d0ba7951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 15:55:37 +0100 Subject: [PATCH 630/753] Disabling benches and beta tests --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 990b4852f..5d6de65c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,16 +17,16 @@ matrix: include: - rust: stable env: FEATURES="--features travis-beta" RUN_TESTS="true" - - rust: beta - env: FEATURES="--features travis-beta" RUN_TESTS="true" + # - rust: beta + # env: FEATURES="--features travis-beta" RUN_TESTS="true" - rust: stable env: FEATURES="--features travis-beta" RUN_BUILD="true" - rust: beta env: FEATURES="--features travis-beta" RUN_BUILD="true" - rust: stable env: FEATURES="--features travis-beta" RUN_COVERAGE="true" - - rust: nightly - env: FEATURES="--features travis-nightly" RUN_BENCHES="true" + # - rust: nightly + # env: FEATURES="--features travis-nightly" RUN_BENCHES="true" - rust: nightly env: FEATURES="--features travis-nightly" RUN_TESTS="true" env: From ab4bfbac0d85c0ee02ed21ca104bee19943ba7fa Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 15 Mar 2016 17:13:44 +0100 Subject: [PATCH 631/753] adding check for a sync --- rpc/src/v1/impls/eth.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index fda391304..66339241e 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -321,6 +321,14 @@ impl Eth for EthClient fn work(&self, params: Params) -> Result { match params { Params::None => { + // check if we a still syncing and return empty strings int that case + { + let sync = take_weak!(self.sync); + if sync.status().state != SyncState::Idle { + return to_value(&(String::new(), String::new(), String::new())); + } + } + let miner = take_weak!(self.miner); let client = take_weak!(self.client); let u = miner.sealing_block(client.deref()).lock().unwrap(); From 99bae239960ba4a90f1cf1dc98c2011cd55d6e3f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 15 Mar 2016 17:56:35 +0100 Subject: [PATCH 632/753] [ci skip] grammar fix --- rpc/src/v1/impls/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 66339241e..0e5d35dca 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -321,7 +321,7 @@ impl Eth for EthClient fn work(&self, params: Params) -> Result { match params { Params::None => { - // check if we a still syncing and return empty strings int that case + // check if we're still syncing and return empty strings int that case { let sync = take_weak!(self.sync); if sync.status().state != SyncState::Idle { From d96858d38c1d6a78ffef8799ddb59eeb6926e847 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 15 Mar 2016 18:17:48 +0100 Subject: [PATCH 633/753] proper blockchain json parsing --- Cargo.lock | 13 +++++ Cargo.toml | 1 + json/Cargo.toml | 21 ++++++++ json/build.rs | 45 ++++++++++++++++ json/src/blockchain/account.rs | 30 +++++++++++ json/src/blockchain/block.rs | 35 +++++++++++++ json/src/blockchain/blockchain.rs | 35 +++++++++++++ json/src/blockchain/header.rs | 51 ++++++++++++++++++ json/src/blockchain/mod.rs | 25 +++++++++ json/src/blockchain/state.rs | 34 ++++++++++++ json/src/blockchain/test.rs | 32 ++++++++++++ json/src/blockchain/transaction.rs | 35 +++++++++++++ json/src/bytes.rs | 81 ++++++++++++++++++++++++++++ json/src/hash.rs | 81 ++++++++++++++++++++++++++++ json/src/lib.rs | 28 ++++++++++ json/src/lib.rs.in | 25 +++++++++ json/src/uint.rs | 84 ++++++++++++++++++++++++++++++ 17 files changed, 656 insertions(+) create mode 100644 json/Cargo.toml create mode 100644 json/build.rs create mode 100644 json/src/blockchain/account.rs create mode 100644 json/src/blockchain/block.rs create mode 100644 json/src/blockchain/blockchain.rs create mode 100644 json/src/blockchain/header.rs create mode 100644 json/src/blockchain/mod.rs create mode 100644 json/src/blockchain/state.rs create mode 100644 json/src/blockchain/test.rs create mode 100644 json/src/blockchain/transaction.rs create mode 100644 json/src/bytes.rs create mode 100644 json/src/hash.rs create mode 100644 json/src/lib.rs create mode 100644 json/src/lib.rs.in create mode 100644 json/src/uint.rs diff --git a/Cargo.lock b/Cargo.lock index dfe37dbb4..f099dc670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "ethcore-devtools 1.1.0", "ethcore-rpc 1.1.0", "ethcore-util 1.1.0", + "ethjson 0.1.0", "ethminer 1.1.0", "ethsync 1.1.0", "fdlimit 0.1.0", @@ -286,6 +287,18 @@ dependencies = [ "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethjson" +version = "0.1.0" +dependencies = [ + "ethcore-util 1.1.0", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethminer" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 782dd1c79..fd1d16cff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } +ethjson = { path = "json" } [features] default = ["rpc"] diff --git a/json/Cargo.toml b/json/Cargo.toml new file mode 100644 index 000000000..61599c331 --- /dev/null +++ b/json/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ethjson" +version = "0.1.0" +authors = ["debris "] +build = "build.rs" + +[dependencies] +ethcore-util = { path = "../util" } +rustc-serialize = "0.3" +serde = "0.7.0" +serde_json = "0.7.0" +serde_macros = { version = "0.7.0", optional = true } +clippy = { version = "0.0.50", optional = true } + +[build-dependencies] +serde_codegen = { version = "0.7.0", optional = true } +syntex = "0.29.0" + +[features] +default = ["serde_codegen"] +nightly = ["serde_macros"] diff --git a/json/build.rs b/json/build.rs new file mode 100644 index 000000000..a23790d86 --- /dev/null +++ b/json/build.rs @@ -0,0 +1,45 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#[cfg(not(feature = "serde_macros"))] +mod inner { + extern crate syntex; + extern crate serde_codegen; + + use std::env; + use std::path::Path; + + pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/lib.rs.in"); + let dst = Path::new(&out_dir).join("lib.rs"); + + let mut registry = syntex::Registry::new(); + + serde_codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} + +#[cfg(feature = "serde_macros")] +mod inner { + pub fn main() {} +} + +fn main() { + inner::main(); +} diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs new file mode 100644 index 000000000..0d72d7fd7 --- /dev/null +++ b/json/src/blockchain/account.rs @@ -0,0 +1,30 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain test account deserializer. + +use std::collections::BTreeMap; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test account deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Account { + balance: Uint, + code: Bytes, + nonce: Uint, + storage: BTreeMap, +} diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs new file mode 100644 index 000000000..5dd423e7c --- /dev/null +++ b/json/src/blockchain/block.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain test block deserializer. + +use uint::Uint; +use bytes::Bytes; +use blockchain::header::Header; +use blockchain::transaction::Transaction; + +/// Blockchain test block deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Block { + #[serde(rename="blockHeader")] + header: Header, + #[serde(rename="blocknumber")] + number: Uint, + rlp: Bytes, + transactions: Vec, + #[serde(rename="uncleHeaders")] + uncles: Vec
, +} diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs new file mode 100644 index 000000000..675e10718 --- /dev/null +++ b/json/src/blockchain/blockchain.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain deserialization. + +use bytes::Bytes; +use blockchain::state::State; +use blockchain::header::Header; + +/// Blockchain deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct BlockChain { + #[serde(rename="genesisBlockHeader")] + genesis_block: Header, + #[serde(rename="genesisRLP")] + genesis_rlp: Bytes, + blocks: Vec
, + #[serde(rename="postState")] + post_state: State, + #[serde(rename="preState")] + pre_state: State, +} diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs new file mode 100644 index 000000000..ea58c76a1 --- /dev/null +++ b/json/src/blockchain/header.rs @@ -0,0 +1,51 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain test header deserializer. + +use hash::Hash; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test header deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Header { + bloom: Hash, // TODO Bloom + coinbase: Hash, + difficulty: Uint, + #[serde(rename="extraData")] + extra_data: Bytes, + #[serde(rename="gasLimit")] + gas_limit: Uint, + #[serde(rename="gasUsed")] + gas_used: Uint, + hash: Hash, + #[serde(rename="mixHash")] + mix_hash: Hash, + nonce: Uint, // TODO fix parsing + number: Uint, + #[serde(rename="parentHash")] + parent_hash: Hash, + #[serde(rename="receiptTrie")] + receipt_trie: Hash, + #[serde(rename="stateRoot")] + state_root: Hash, + timestamp: Uint, + #[serde(rename="transactionsTrie")] + transactions_trie: Hash, + #[serde(rename="uncleHash")] + uncle_hash: Hash, +} diff --git a/json/src/blockchain/mod.rs b/json/src/blockchain/mod.rs new file mode 100644 index 000000000..046b2e534 --- /dev/null +++ b/json/src/blockchain/mod.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain test deserialization. + +pub mod account; +pub mod block; +pub mod blockchain; +pub mod header; +pub mod state; +pub mod transaction; +pub mod test; diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs new file mode 100644 index 000000000..c934d7c0a --- /dev/null +++ b/json/src/blockchain/state.rs @@ -0,0 +1,34 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain test state deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use hash::Hash; +use blockchain::account::Account; + +/// Blockchain test state deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct State(BTreeMap); + +impl Deref for State { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs new file mode 100644 index 000000000..6097a60e6 --- /dev/null +++ b/json/src/blockchain/test.rs @@ -0,0 +1,32 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain test deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use blockchain::blockchain::BlockChain; + +/// Blockchain test deserializer. +pub struct Test(BTreeMap); + +impl Deref for Test { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/json/src/blockchain/transaction.rs b/json/src/blockchain/transaction.rs new file mode 100644 index 000000000..5d04748f5 --- /dev/null +++ b/json/src/blockchain/transaction.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain test transaction deserialization. + +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test transaction deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Transaction { + data: Bytes, + #[serde(rename="gasLimit")] + gas_limit: Uint, + #[serde(rename="gasPrice")] + gas_price: Uint, + nonce: Uint, + r: Uint, + s: Uint, + v: Uint, + value: Uint +} diff --git a/json/src/bytes.rs b/json/src/bytes.rs new file mode 100644 index 000000000..034c90d62 --- /dev/null +++ b/json/src/bytes.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Lenient bytes json deserialization for test json files. + +use rustc_serialize::hex::FromHex; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; + +/// Lenient bytes json deserialization for test json files. +#[derive(Default, Debug, PartialEq)] +pub struct Bytes(Vec); + +impl Into> for Bytes { + fn into(self) -> Vec { + self.0 + } +} + +impl Deserialize for Bytes { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(BytesVisitor) + } +} + +struct BytesVisitor; + +impl Visitor for BytesVisitor { + type Value = Bytes; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let v = match value.len() { + 0 => vec![], + 2 if value.starts_with("0x") => vec![], + _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| Error::custom("Invalid hex value."))), + _ => try!(FromHex::from_hex(value).map_err(|_| Error::custom("Invalid hex value"))) + }; + Ok(Bytes(v)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +//mod test { + //use std::str::FromStr; + //use serde_json; + //use util::hash::H256; + //use hash::Hash; + + //#[test] + //fn uint_deserialization() { + //let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; + //let deserialized: Vec = serde_json::from_str(s).unwrap(); + //assert_eq!(deserialized, vec![ + //Hash(H256::from(0)), + //Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + //]); + //} + + //#[test] + //fn uint_into() { + //assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + //} +//} diff --git a/json/src/hash.rs b/json/src/hash.rs new file mode 100644 index 000000000..e5bbedbfa --- /dev/null +++ b/json/src/hash.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Lenient hash json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::hash::H256; + +/// Lenient hash json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Hash(H256); + +impl Into for Hash { + fn into(self) -> H256 { + self.0 + } +} + +impl Deserialize for Hash { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(HashVisitor) + } +} + +struct HashVisitor; + +impl Visitor for HashVisitor { + type Value = Hash; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => H256::from(0), + _ => try!(H256::from_str(value).map_err(|_| Error::custom("invalid hex value."))) + }; + + Ok(Hash(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use std::str::FromStr; + use serde_json; + use util::hash::H256; + use hash::Hash; + + #[test] + fn uint_deserialization() { + let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Hash(H256::from(0)), + Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + ]); + } + + #[test] + fn uint_into() { + assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + } +} diff --git a/json/src/lib.rs b/json/src/lib.rs new file mode 100644 index 000000000..b94e1fa55 --- /dev/null +++ b/json/src/lib.rs @@ -0,0 +1,28 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Json deserialization module. + +#![warn(missing_docs)] +#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] + +#[cfg(feature = "serde_macros")] +include!("lib.rs.in"); + +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/lib.rs")); + diff --git a/json/src/lib.rs.in b/json/src/lib.rs.in new file mode 100644 index 000000000..6d3437811 --- /dev/null +++ b/json/src/lib.rs.in @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate rustc_serialize; +extern crate serde; +extern crate serde_json; +extern crate ethcore_util as util; + +pub mod hash; +pub mod uint; +pub mod bytes; +pub mod blockchain; diff --git a/json/src/uint.rs b/json/src/uint.rs new file mode 100644 index 000000000..f7f34f1dd --- /dev/null +++ b/json/src/uint.rs @@ -0,0 +1,84 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Lenient uint json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::numbers::{U256, Uint as U}; + +/// Lenient uint json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Uint(U256); + +impl Into for Uint { + fn into(self) -> U256 { + self.0 + } +} + +impl Deserialize for Uint { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(UintVisitor) + } +} + +struct UintVisitor; + +impl Visitor for UintVisitor { + type Value = Uint; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => U256::from(0), + 2 if value.starts_with("0x") => U256::from(0), + _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| Error::custom("invalid hex value."))), + _ => try!(U256::from_dec_str(value).map_err(|_| Error::custom("invalid decimal value."))) + }; + + Ok(Uint(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use serde_json; + use util::numbers::U256; + use uint::Uint; + + #[test] + fn uint_deserialization() { + let s = r#"["0xa", "10", "", "0x"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Uint(U256::from(10)), + Uint(U256::from(10)), + Uint(U256::from(0)), + Uint(U256::from(0)) + ]); + } + + #[test] + fn uint_into() { + assert_eq!(U256::from(10), Uint(U256::from(10)).into()); + } +} From e538b417f005303dc95e7ece9f9ca77134a5edfa Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 15 Mar 2016 18:14:52 +0100 Subject: [PATCH 634/753] Missing return --- sync/src/chain.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 363597d40..8f0194289 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -481,6 +481,7 @@ impl ChainSync { trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); if !self.have_common_block { trace!(target: "sync", "NewBlock ignored while seeking"); + return Ok(()); } let header: BlockHeader = try!(header_rlp.as_val()); let mut unknown = false; @@ -1497,6 +1498,7 @@ mod tests { let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); + sync.have_common_block = true; let mut io = TestIo::new(&mut client, &mut queue, None); let block = UntrustedRlp::new(&block_data); From b4849d1c5870db13020f356bdffe4cee7c6a7161 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 15 Mar 2016 18:23:59 +0100 Subject: [PATCH 635/753] finished blockchain test deserialization --- json/src/blockchain/header.rs | 22 ++++----- json/src/blockchain/state.rs | 6 +-- json/src/bytes.rs | 40 +++++++-------- json/src/hash.rs | 91 ++++++++++++++++++++--------------- 4 files changed, 86 insertions(+), 73 deletions(-) diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index ea58c76a1..fc27fc1f5 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -16,15 +16,15 @@ //! Blockchain test header deserializer. -use hash::Hash; +use hash::{H64, H256, Bloom}; use uint::Uint; use bytes::Bytes; /// Blockchain test header deserializer. #[derive(Debug, PartialEq, Deserialize)] pub struct Header { - bloom: Hash, // TODO Bloom - coinbase: Hash, + bloom: Bloom, + coinbase: H256, difficulty: Uint, #[serde(rename="extraData")] extra_data: Bytes, @@ -32,20 +32,20 @@ pub struct Header { gas_limit: Uint, #[serde(rename="gasUsed")] gas_used: Uint, - hash: Hash, + hash: H256, #[serde(rename="mixHash")] - mix_hash: Hash, - nonce: Uint, // TODO fix parsing + mix_hash: H256, + nonce: H64, number: Uint, #[serde(rename="parentHash")] - parent_hash: Hash, + parent_hash: H256, #[serde(rename="receiptTrie")] - receipt_trie: Hash, + receipt_trie: H256, #[serde(rename="stateRoot")] - state_root: Hash, + state_root: H256, timestamp: Uint, #[serde(rename="transactionsTrie")] - transactions_trie: Hash, + transactions_trie: H256, #[serde(rename="uncleHash")] - uncle_hash: Hash, + uncle_hash: H256, } diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs index c934d7c0a..2af0dbf21 100644 --- a/json/src/blockchain/state.rs +++ b/json/src/blockchain/state.rs @@ -18,15 +18,15 @@ use std::collections::BTreeMap; use std::ops::Deref; -use hash::Hash; +use hash::Address; use blockchain::account::Account; /// Blockchain test state deserializer. #[derive(Debug, PartialEq, Deserialize)] -pub struct State(BTreeMap); +pub struct State(BTreeMap); impl Deref for State { - type Target = BTreeMap; + type Target = BTreeMap; fn deref(&self) -> &Self::Target { &self.0 diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 034c90d62..c9e31e888 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -58,24 +58,26 @@ impl Visitor for BytesVisitor { } #[cfg(test)] -//mod test { - //use std::str::FromStr; - //use serde_json; - //use util::hash::H256; - //use hash::Hash; +mod test { + use serde_json; + use bytes::Bytes; - //#[test] - //fn uint_deserialization() { - //let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; - //let deserialized: Vec = serde_json::from_str(s).unwrap(); - //assert_eq!(deserialized, vec![ - //Hash(H256::from(0)), - //Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) - //]); - //} + #[test] + fn bytes_deserialization() { + let s = r#"["", "0x", "0x12", "1234"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Bytes(vec![]), + Bytes(vec![]), + Bytes(vec![0x12]), + Bytes(vec![0x12, 0x34]) + ]); + } - //#[test] - //fn uint_into() { - //assert_eq!(H256::from(0), Hash(H256::from(0)).into()); - //} -//} + #[test] + fn bytes_into() { + let bytes = Bytes(vec![0xff, 0x11]); + let v: Vec = bytes.into(); + assert_eq!(vec![0xff, 0x11], v); + } +} diff --git a/json/src/hash.rs b/json/src/hash.rs index e5bbedbfa..8ed28c33c 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -19,63 +19,74 @@ use std::str::FromStr; use serde::{Deserialize, Deserializer, Error}; use serde::de::Visitor; -use util::hash::H256; +use util::hash::{H64 as Hash64, Address as Hash160, H256 as Hash256, H2048 as Hash2048}; -/// Lenient hash json deserialization for test json files. -#[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Hash(H256); -impl Into for Hash { - fn into(self) -> H256 { - self.0 +macro_rules! impl_hash { + ($name: ident, $inner: ident) => { + /// Lenient hash json deserialization for test json files. + #[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct $name($inner); + + impl Into<$inner> for $name { + fn into(self) -> $inner { + self.0 + } + } + + impl Deserialize for $name { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + + struct HashVisitor; + + impl Visitor for HashVisitor { + type Value = $name; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => $inner::from(0), + _ => try!($inner::from_str(value).map_err(|_| Error::custom("invalid hex value."))) + }; + + Ok($name(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } + } + + deserializer.deserialize(HashVisitor) + } + } } } -impl Deserialize for Hash { - fn deserialize(deserializer: &mut D) -> Result - where D: Deserializer { - deserializer.deserialize(HashVisitor) - } -} - -struct HashVisitor; - -impl Visitor for HashVisitor { - type Value = Hash; - - fn visit_str(&mut self, value: &str) -> Result where E: Error { - let value = match value.len() { - 0 => H256::from(0), - _ => try!(H256::from_str(value).map_err(|_| Error::custom("invalid hex value."))) - }; - - Ok(Hash(value)) - } - - fn visit_string(&mut self, value: String) -> Result where E: Error { - self.visit_str(value.as_ref()) - } -} +impl_hash!(H64, Hash64); +impl_hash!(Address, Hash160); +impl_hash!(H256, Hash256); +impl_hash!(Bloom, Hash2048); #[cfg(test)] mod test { use std::str::FromStr; use serde_json; - use util::hash::H256; - use hash::Hash; + use util::hash; + use hash::H256; #[test] - fn uint_deserialization() { + fn hash_deserialization() { let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; - let deserialized: Vec = serde_json::from_str(s).unwrap(); + let deserialized: Vec = serde_json::from_str(s).unwrap(); assert_eq!(deserialized, vec![ - Hash(H256::from(0)), - Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + H256(hash::H256::from(0)), + H256(hash::H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) ]); } #[test] - fn uint_into() { - assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + fn hash_into() { + assert_eq!(hash::H256::from(0), H256(hash::H256::from(0)).into()); } } From 196c6e8eccb73b885596e5225ce714abff35c80e Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 15 Mar 2016 19:32:07 +0100 Subject: [PATCH 636/753] tests for loading test json files --- json/src/blockchain/account.rs | 20 ++++++ json/src/blockchain/block.rs | 39 +++++++++- json/src/blockchain/blockchain.rs | 114 +++++++++++++++++++++++++++++- json/src/blockchain/header.rs | 34 ++++++++- json/src/bytes.rs | 8 ++- json/src/hash.rs | 4 +- json/src/uint.rs | 8 ++- 7 files changed, 215 insertions(+), 12 deletions(-) diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs index 0d72d7fd7..eb6f0a1dd 100644 --- a/json/src/blockchain/account.rs +++ b/json/src/blockchain/account.rs @@ -28,3 +28,23 @@ pub struct Account { nonce: Uint, storage: BTreeMap, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::account::Account; + + #[test] + fn header_deserialization() { + let s = r#"{ + "balance" : "0x09184e72a078", + "code" : "0x600140600155", + "nonce" : "0x00", + "storage" : { + "0x01" : "0x9a10c2b5bb8f3c602e674006d9b21f09167df57c87a78a5ce96d4159ecb76520" + } + }"#; + let _deserialized: Account= serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs index 5dd423e7c..ed297077c 100644 --- a/json/src/blockchain/block.rs +++ b/json/src/blockchain/block.rs @@ -16,7 +16,6 @@ //! Blockchain test block deserializer. -use uint::Uint; use bytes::Bytes; use blockchain::header::Header; use blockchain::transaction::Transaction; @@ -26,10 +25,44 @@ use blockchain::transaction::Transaction; pub struct Block { #[serde(rename="blockHeader")] header: Header, - #[serde(rename="blocknumber")] - number: Uint, rlp: Bytes, transactions: Vec, #[serde(rename="uncleHeaders")] uncles: Vec
, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::block::Block; + + #[test] + fn block_deserialization() { + let s = r#"{ + "blockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x00", + "hash" : "65ebf1b97fb89b14680267e0723d69267ec4bf9a96d4a60ffcb356ae0e81c18f", + "mixHash" : "13735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd06", + "nonce" : "931dcc53e5edc514", + "number" : "0x01", + "parentHash" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3", + "timestamp" : "0x56850b7b", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "blocknumber" : "1", + "rlp" : "0xf901fcf901f7a05a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefba808456850b7b80a013735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd0688931dcc53e5edc514c0c0", + "transactions" : [], + "uncleHeaders" : [] + }"#; + let _deserialized: Block = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 675e10718..f6b1259ca 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -19,6 +19,7 @@ use bytes::Bytes; use blockchain::state::State; use blockchain::header::Header; +use blockchain::block::Block; /// Blockchain deserialization. #[derive(Debug, PartialEq, Deserialize)] @@ -27,9 +28,118 @@ pub struct BlockChain { genesis_block: Header, #[serde(rename="genesisRLP")] genesis_rlp: Bytes, - blocks: Vec
, + blocks: Vec, #[serde(rename="postState")] post_state: State, - #[serde(rename="preState")] + #[serde(rename="pre")] pre_state: State, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::blockchain::BlockChain; + + #[test] + fn blockchain_deserialization() { + let s = r#"{ + "blocks" : [{ + "blockHeader" : { + "bloom" : "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x0102030405060708091011121314151617181920212223242526272829303132", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x560b", + "hash" : "06b5b1742bde29468510c92641f36b719c61b3fc3e9a21c92a23978f4f7faa2a", + "mixHash" : "5266ca43e81d25925a9ba573c3e4f9180bc076d316d90e63c6f8708b272f5ce2", + "nonce" : "59ba4daed1898e21", + "number" : "0x01", + "parentHash" : "f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524d", + "receiptTrie" : "c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296", + "stateRoot" : "bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bf", + "timestamp" : "0x56850c2c", + "transactionsTrie" : "498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "rlp" : "0xf90285f90219a0f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefba82560b8456850c2ca00102030405060708091011121314151617181920212223242526272829303132a05266ca43e81d25925a9ba573c3e4f9180bc076d316d90e63c6f8708b272f5ce28859ba4daed1898e21f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0", + "transactions" : [ + { + "data" : "0x", + "gasLimit" : "0xc350", + "gasPrice" : "0x0a", + "nonce" : "0x00", + "r" : "0xee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3", + "s" : "0x4e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "0x1c", + "value" : "0x012a05f200" + } + ], + "uncleHeaders" : [ + ] + }], + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x42", + "gasLimit" : "0x2fefd8", + "gasUsed" : "0x00", + "hash" : "f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524d", + "mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0102030405060708", + "number" : "0x00", + "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0", + "lastblockhash" : "06b5b1742bde29468510c92641f36b719c61b3fc3e9a21c92a23978f4f7faa2a", + "postState" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x012a05f264", + "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1", + "nonce" : "0x00", + "storage" : { + } + }, + "8888f1f195afa192cfee860698584c030f4c9db1" : { + "balance" : "0x4563918244f75c6e", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x012a029592", + "code" : "0x", + "nonce" : "0x01", + "storage" : { + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x64", + "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x02540be400", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + } + } + }"#; + let _deserialized: BlockChain = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + //} +} diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index fc27fc1f5..e97039213 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -16,7 +16,7 @@ //! Blockchain test header deserializer. -use hash::{H64, H256, Bloom}; +use hash::{H64, Address, H256, Bloom}; use uint::Uint; use bytes::Bytes; @@ -24,7 +24,7 @@ use bytes::Bytes; #[derive(Debug, PartialEq, Deserialize)] pub struct Header { bloom: Bloom, - coinbase: H256, + coinbase: Address, difficulty: Uint, #[serde(rename="extraData")] extra_data: Bytes, @@ -49,3 +49,33 @@ pub struct Header { #[serde(rename="uncleHash")] uncle_hash: H256, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::header::Header; + + #[test] + fn header_deserialization() { + let s = r#"{ + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x00", + "hash" : "65ebf1b97fb89b14680267e0723d69267ec4bf9a96d4a60ffcb356ae0e81c18f", + "mixHash" : "13735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd06", + "nonce" : "931dcc53e5edc514", + "number" : "0x01", + "parentHash" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3", + "timestamp" : "0x56850b7b", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }"#; + let _deserialized: Header = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/bytes.rs b/json/src/bytes.rs index c9e31e888..28b7636d4 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -46,8 +46,12 @@ impl Visitor for BytesVisitor { let v = match value.len() { 0 => vec![], 2 if value.starts_with("0x") => vec![], - _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| Error::custom("Invalid hex value."))), - _ => try!(FromHex::from_hex(value).map_err(|_| Error::custom("Invalid hex value"))) + _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })), + _ => try!(FromHex::from_hex(value).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })) }; Ok(Bytes(v)) } diff --git a/json/src/hash.rs b/json/src/hash.rs index 8ed28c33c..098f2e7a8 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -46,7 +46,9 @@ macro_rules! impl_hash { fn visit_str(&mut self, value: &str) -> Result where E: Error { let value = match value.len() { 0 => $inner::from(0), - _ => try!($inner::from_str(value).map_err(|_| Error::custom("invalid hex value."))) + _ => try!($inner::from_str(value).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })) }; Ok($name(value)) diff --git a/json/src/uint.rs b/json/src/uint.rs index f7f34f1dd..41e717277 100644 --- a/json/src/uint.rs +++ b/json/src/uint.rs @@ -47,8 +47,12 @@ impl Visitor for UintVisitor { let value = match value.len() { 0 => U256::from(0), 2 if value.starts_with("0x") => U256::from(0), - _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| Error::custom("invalid hex value."))), - _ => try!(U256::from_dec_str(value).map_err(|_| Error::custom("invalid decimal value."))) + _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })), + _ => try!(U256::from_dec_str(value).map_err(|_| { + Error::custom(format!("Invalid decimal value {}.", value).as_ref()) + })) }; Ok(Uint(value)) From 188e325b2060ab30377ba97764f4fbae6a27da0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 23:01:36 +0100 Subject: [PATCH 637/753] Importing transactions from hashset. Notifying about every block --- ethcore/src/client/client.rs | 2 +- miner/src/miner.rs | 34 +++++++++++++++++++++++----------- miner/src/transaction_queue.rs | 10 ++++++++++ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index caa92db97..6857416d3 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -317,7 +317,7 @@ impl Client where V: Verifier { } { - if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { + if !imported_blocks.is_empty() { let (enacted, retracted) = self.calculate_enacted_retracted(import_results); io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { imported: imported_blocks, diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 6d5b3086e..4652ab3db 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -18,6 +18,7 @@ use rayon::prelude::*; use std::sync::{Mutex, RwLock, Arc}; use std::sync::atomic; use std::sync::atomic::AtomicBool; +use std::collections::HashSet; use util::{H256, U256, Address, Bytes, Uint}; use ethcore::views::{BlockView}; @@ -174,21 +175,10 @@ impl MinerService for Miner { let block = BlockView::new(&block); block.transactions() } - { - let in_chain = vec![imported, enacted, invalid]; - let in_chain = in_chain - .par_iter() - .flat_map(|h| h.par_iter().map(|h| fetch_transactions(chain, h))); let out_of_chain = retracted .par_iter() .map(|h| fetch_transactions(chain, h)); - - in_chain.for_each(|txs| { - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); - transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); - }); out_of_chain.for_each(|txs| { // populate sender for tx in &txs { @@ -198,6 +188,28 @@ impl MinerService for Miner { let _ = transaction_queue.add_all(txs, |a| chain.nonce(a)); }); } + // First import all transactions and after that remove old ones + { + let in_chain = { + let mut in_chain = HashSet::new(); + in_chain.extend(imported); + in_chain.extend(enacted); + in_chain.extend(invalid); + in_chain + .into_iter() + .collect::>() + }; + + let in_chain = in_chain + .par_iter() + .map(|h: &H256| fetch_transactions(chain, h)); + + in_chain.for_each(|txs| { + let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); + }); + } if self.sealing_enabled.load(atomic::Ordering::Relaxed) { self.prepare_sealing(chain); diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 324a46364..04febb84d 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -351,6 +351,8 @@ impl TransactionQueue { /// If gap is introduced marks subsequent transactions as future pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &T) where T: Fn(&Address) -> U256 { + + println!("Removing transaction: (hash: {:?})", transaction_hash); let transaction = self.by_hash.remove(transaction_hash); if transaction.is_none() { // We don't know this transaction @@ -362,6 +364,8 @@ impl TransactionQueue { let nonce = transaction.nonce(); let current_nonce = fetch_nonce(&sender); + println!("Removing transaction: ({:?}, {:?}, hash: {:?})", sender, nonce, transaction.hash()); + // Remove from future let order = self.future.drop(&sender, &nonce); if order.is_some() { @@ -489,12 +493,14 @@ impl TransactionQueue { fn import_tx(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) where T: Fn(&Address) -> U256 { + if self.by_hash.get(&tx.hash()).is_some() { // Transaction is already imported. trace!(target: "sync", "Dropping already imported transaction with hash: {:?}", tx.hash()); return; } + let address = tx.sender(); let nonce = tx.nonce(); @@ -506,6 +512,7 @@ impl TransactionQueue { // Check height if nonce > next_nonce { + println!("[F] Importing transaction: ({:?}, {:?}, hash: {:?}, gas: {:?})", tx.sender(), tx.nonce(), tx.hash(), tx.transaction.gas_price); // We have a gap - put to future Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash); self.future.enforce_limit(&mut self.by_hash); @@ -515,6 +522,7 @@ impl TransactionQueue { trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); return; } + println!("[C] Importing transaction: ({:?}, {:?}, hash: {:?}, gas: {:?})", tx.sender(), tx.nonce(), tx.hash(), tx.transaction.gas_price); Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash); self.last_nonces.insert(address, nonce); @@ -540,11 +548,13 @@ impl TransactionQueue { let new_fee = order.gas_price; if old_fee.cmp(&new_fee) == Ordering::Greater { // Put back old transaction since it has greater priority (higher gas_price) + println!("Didn't replace tx (h:{:?}, h:{:?})", hash, old.hash); set.by_address.insert(address, nonce, old); // and remove new one set.by_priority.remove(&order); by_hash.remove(&hash); } else { + println!("Replaced h:{:?} with h:{:?}, ", old.hash, hash); // Make sure we remove old transaction entirely set.by_priority.remove(&old); by_hash.remove(&old.hash); From 974222aabd114ba9e96c125aa622cf66ef408876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 15 Mar 2016 23:13:53 +0100 Subject: [PATCH 638/753] Removing printlns --- miner/src/transaction_queue.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 04febb84d..4b365bba2 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -352,7 +352,6 @@ impl TransactionQueue { pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &T) where T: Fn(&Address) -> U256 { - println!("Removing transaction: (hash: {:?})", transaction_hash); let transaction = self.by_hash.remove(transaction_hash); if transaction.is_none() { // We don't know this transaction @@ -364,7 +363,6 @@ impl TransactionQueue { let nonce = transaction.nonce(); let current_nonce = fetch_nonce(&sender); - println!("Removing transaction: ({:?}, {:?}, hash: {:?})", sender, nonce, transaction.hash()); // Remove from future let order = self.future.drop(&sender, &nonce); @@ -512,7 +510,6 @@ impl TransactionQueue { // Check height if nonce > next_nonce { - println!("[F] Importing transaction: ({:?}, {:?}, hash: {:?}, gas: {:?})", tx.sender(), tx.nonce(), tx.hash(), tx.transaction.gas_price); // We have a gap - put to future Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash); self.future.enforce_limit(&mut self.by_hash); @@ -522,7 +519,6 @@ impl TransactionQueue { trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); return; } - println!("[C] Importing transaction: ({:?}, {:?}, hash: {:?}, gas: {:?})", tx.sender(), tx.nonce(), tx.hash(), tx.transaction.gas_price); Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash); self.last_nonces.insert(address, nonce); @@ -548,13 +544,11 @@ impl TransactionQueue { let new_fee = order.gas_price; if old_fee.cmp(&new_fee) == Ordering::Greater { // Put back old transaction since it has greater priority (higher gas_price) - println!("Didn't replace tx (h:{:?}, h:{:?})", hash, old.hash); set.by_address.insert(address, nonce, old); // and remove new one set.by_priority.remove(&order); by_hash.remove(&hash); } else { - println!("Replaced h:{:?} with h:{:?}, ", old.hash, hash); // Make sure we remove old transaction entirely set.by_priority.remove(&old); by_hash.remove(&old.hash); From 8427e99c73f6ed3d0db427ef4a9e42ef0410b0ba Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 15 Mar 2016 23:58:46 +0100 Subject: [PATCH 639/753] checking queue also --- rpc/src/v1/impls/eth.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 0e5d35dca..32e9b44b1 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -321,10 +321,11 @@ impl Eth for EthClient fn work(&self, params: Params) -> Result { match params { Params::None => { + let client = take_weak!(self.client); // check if we're still syncing and return empty strings int that case { let sync = take_weak!(self.sync); - if sync.status().state != SyncState::Idle { + if sync.status().state != SyncState::Idle && client.queue_info().is_empty() { return to_value(&(String::new(), String::new(), String::new())); } } From bd892026f632df65e4b5b075295a670eac85d422 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 16 Mar 2016 10:37:08 +0100 Subject: [PATCH 640/753] tests --- rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/tests/eth.rs | 28 +++++++++++++++++++---- rpc/src/v1/tests/helpers/miner_service.rs | 20 +++++++++++++--- rpc/src/v1/tests/helpers/sync_provider.rs | 9 ++++---- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 32e9b44b1..520b37045 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -340,7 +340,7 @@ impl Eth for EthClient let seed_hash = Ethash::get_seedhash(b.block().header().number()); to_value(&(pow_hash, seed_hash, target)) } - _ => Err(Error::invalid_params()) + _ => Err(Error::internal_error()) } }, _ => Err(Error::invalid_params()) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 6bc929709..280557e4b 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -43,12 +43,12 @@ fn sync_provider() -> Arc { } fn miner_service() -> Arc { - Arc::new(TestMinerService) + Arc::new(TestMinerService::default()) } struct EthTester { - client: Arc, - _sync: Arc, + pub client: Arc, + pub sync: Arc, _accounts_provider: Arc, _miner: Arc, hashrates: Arc>>, @@ -68,7 +68,7 @@ impl Default for EthTester { io.add_delegate(eth); EthTester { client: client, - _sync: sync, + sync: sync, _accounts_provider: ap, _miner: miner, io: io, @@ -346,5 +346,25 @@ fn rpc_eth_compile_serpent() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +fn returns_no_work_if_cant_mine() { + let eth_tester = EthTester::default(); + let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":["","",""],"id":1}"#; + assert_eq!(eth_tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn returns_error_if_can_mine_and_no_closed_block() { + use ethsync::{SyncState}; + + let eth_tester = EthTester::default(); + eth_tester.sync.status.write().unwrap().state = SyncState::Idle; + + let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + assert_eq!(eth_tester.io.handle_request(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 0cddf2a1e..3a60bd136 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -22,7 +22,19 @@ use ethcore::block::ClosedBlock; use ethcore::transaction::SignedTransaction; use ethminer::{MinerService, MinerStatus}; -pub struct TestMinerService; +pub struct TestMinerService { + pub imported_transactions: RwLock>, + pub latest_closed_block: Mutex>, +} + +impl Default for TestMinerService { + fn default() -> TestMinerService { + TestMinerService { + imported_transactions: RwLock::new(Vec::new()), + latest_closed_block: Mutex::new(None), + } + } +} impl MinerService for TestMinerService { @@ -45,9 +57,11 @@ impl MinerService for TestMinerService { fn prepare_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex> { unimplemented!(); } + fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex> { + &self.latest_closed_block + } /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { unimplemented!(); } -} \ No newline at end of file +} diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index 631752dfc..bfbfad44b 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use ethsync::{SyncProvider, SyncStatus, SyncState}; +use std::sync::{RwLock}; pub struct Config { pub protocol_version: u8, @@ -22,13 +23,13 @@ pub struct Config { } pub struct TestSyncProvider { - status: SyncStatus, + pub status: RwLock, } impl TestSyncProvider { pub fn new(config: Config) -> Self { TestSyncProvider { - status: SyncStatus { + status: RwLock::new(SyncStatus { state: SyncState::NotSynced, protocol_version: config.protocol_version, start_block_number: 0, @@ -39,14 +40,14 @@ impl TestSyncProvider { num_peers: config.num_peers, num_active_peers: 0, mem_used: 0, - }, + }) } } } impl SyncProvider for TestSyncProvider { fn status(&self) -> SyncStatus { - self.status.clone() + self.status.read().unwrap().clone() } } From fdba8de6000e8d629d7bc4a504a8cedb03d6168f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 16 Mar 2016 10:40:33 +0100 Subject: [PATCH 641/753] Validating senders balance before importing transaction to queue --- ethcore/src/error.rs | 9 ++- miner/src/lib.rs | 8 +-- miner/src/miner.rs | 20 ++++-- miner/src/transaction_queue.rs | 81 +++++++++++++++-------- rpc/src/v1/impls/eth.rs | 7 +- rpc/src/v1/tests/helpers/miner_service.rs | 7 +- sync/src/chain.rs | 9 ++- 7 files changed, 94 insertions(+), 47 deletions(-) diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 72127c754..482a8de01 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -70,7 +70,14 @@ pub enum TransactionError { /// Minimal expected gas price minimal: U256, /// Transaction gas price - got: U256 + got: U256, + }, + /// Sender doesn't have enough funds to pay for this transaction + InsufficientBalance { + /// Senders balance + balance: U256, + /// Transaction cost + cost: U256, }, /// Transaction's gas limit (aka gas) is invalid. InvalidGasLimit(OutOfBounds), diff --git a/miner/src/lib.rs b/miner/src/lib.rs index a431bd44e..3c9775268 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -62,11 +62,11 @@ extern crate rayon; mod miner; mod transaction_queue; -pub use transaction_queue::TransactionQueue; +pub use transaction_queue::{TransactionQueue, AccountDetails}; pub use miner::{Miner}; use std::sync::Mutex; -use util::{H256, U256, Address, Bytes}; +use util::{H256, Address, Bytes}; use ethcore::client::{BlockChainClient}; use ethcore::block::{ClosedBlock}; use ethcore::error::{Error}; @@ -79,8 +79,8 @@ pub trait MinerService : Send + Sync { fn status(&self) -> MinerStatus; /// Imports transactions to transaction queue. - fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> - where T: Fn(&Address) -> U256; + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Result<(), Error> + where T: Fn(&Address) -> AccountDetails; /// Returns hashes of transactions currently in pending fn pending_transactions_hashes(&self) -> Vec; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 4652ab3db..27cf2ded2 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -26,7 +26,7 @@ use ethcore::client::{BlockChainClient, BlockId}; use ethcore::block::{ClosedBlock}; use ethcore::error::{Error}; use ethcore::transaction::SignedTransaction; -use super::{MinerService, MinerStatus, TransactionQueue}; +use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails}; /// Keeps track of transactions using priority queue and holds currently mined block. pub struct Miner { @@ -72,7 +72,7 @@ impl Miner { /// Get the extra_data that we will seal blocks wuth. fn gas_floor_target(&self) -> U256 { - self.gas_floor_target.read().unwrap().clone() + *self.gas_floor_target.read().unwrap() } /// Set the author that we will seal blocks as. @@ -111,10 +111,10 @@ impl MinerService for Miner { } } - fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> - where T: Fn(&Address) -> U256 { + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Result<(), Error> + where T: Fn(&Address) -> AccountDetails { let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(transactions, fetch_nonce) + transaction_queue.add_all(transactions, fetch_account) } fn pending_transactions_hashes(&self) -> Vec { @@ -185,7 +185,10 @@ impl MinerService for Miner { let _sender = tx.sender(); } let mut transaction_queue = self.transaction_queue.lock().unwrap(); - let _ = transaction_queue.add_all(txs, |a| chain.nonce(a)); + let _ = transaction_queue.add_all(txs, |a| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a) + }); }); } // First import all transactions and after that remove old ones @@ -207,7 +210,10 @@ impl MinerService for Miner { in_chain.for_each(|txs| { let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); + transaction_queue.remove_all(&hashes, |a| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a) + }); }); } diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 4b365bba2..ca4a269ae 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -232,8 +232,6 @@ impl TransactionSet { } } -// Will be used when rpc merged -#[allow(dead_code)] #[derive(Debug)] /// Current status of the queue pub struct TransactionQueueStatus { @@ -243,6 +241,14 @@ pub struct TransactionQueueStatus { pub future: usize, } +/// Details of account +pub struct AccountDetails { + /// Most recent account nonce + pub nonce: U256, + /// Current account balance + pub balance: U256, +} + /// TransactionQueue implementation pub struct TransactionQueue { /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) @@ -308,49 +314,63 @@ impl TransactionQueue { } /// Adds all signed transactions to queue to be verified and imported - pub fn add_all(&mut self, txs: Vec, fetch_nonce: T) -> Result<(), Error> - where T: Fn(&Address) -> U256 { + pub fn add_all(&mut self, txs: Vec, fetch_account: T) -> Result<(), Error> + where T: Fn(&Address) -> AccountDetails { for tx in txs.into_iter() { - try!(self.add(tx, &fetch_nonce)); + try!(self.add(tx, &fetch_account)); } Ok(()) } /// Add signed transaction to queue to be verified and imported - pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) -> Result<(), Error> - where T: Fn(&Address) -> U256 { + pub fn add(&mut self, tx: SignedTransaction, fetch_account: &T) -> Result<(), Error> + where T: Fn(&Address) -> AccountDetails { + + trace!(target: "miner", "Importing: {:?}", tx.hash()); if tx.gas_price < self.minimal_gas_price { - trace!(target: "sync", + trace!(target: "miner", "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", tx.hash(), tx.gas_price, self.minimal_gas_price ); return Err(Error::Transaction(TransactionError::InsufficientGasPrice{ minimal: self.minimal_gas_price, - got: tx.gas_price + got: tx.gas_price, })); } - self.import_tx(try!(VerifiedTransaction::new(tx)), fetch_nonce); + let vtx = try!(VerifiedTransaction::new(tx)); + let account = fetch_account(&vtx.sender()); + + if account.balance < vtx.transaction.value { + trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})", + vtx.hash(), account.balance, vtx.transaction.value); + return Err(Error::Transaction(TransactionError::InsufficientBalance { + cost: vtx.transaction.value, + balance: account.balance + })); + } + + self.import_tx(vtx, account.nonce); Ok(()) } /// Removes all transactions identified by hashes given in slice /// /// If gap is introduced marks subsequent transactions as future - pub fn remove_all(&mut self, transaction_hashes: &[H256], fetch_nonce: T) - where T: Fn(&Address) -> U256 { + pub fn remove_all(&mut self, transaction_hashes: &[H256], fetch_account: T) + where T: Fn(&Address) -> AccountDetails { for hash in transaction_hashes { - self.remove(&hash, &fetch_nonce); + self.remove(&hash, &fetch_account); } } /// Removes transaction identified by hashes from queue. /// /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &T) - where T: Fn(&Address) -> U256 { + pub fn remove(&mut self, transaction_hash: &H256, fetch_account: &T) + where T: Fn(&Address) -> AccountDetails { let transaction = self.by_hash.remove(transaction_hash); if transaction.is_none() { @@ -361,7 +381,7 @@ impl TransactionQueue { let transaction = transaction.unwrap(); let sender = transaction.sender(); let nonce = transaction.nonce(); - let current_nonce = fetch_nonce(&sender); + let current_nonce = fetch_account(&sender).nonce; // Remove from future @@ -403,6 +423,7 @@ impl TransactionQueue { if k >= current_nonce { self.future.insert(*sender, k, order.update_height(k, current_nonce)); } else { + trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); // Remove the transaction completely self.by_hash.remove(&order.hash); } @@ -423,6 +444,7 @@ impl TransactionQueue { if k >= current_nonce { self.future.insert(*sender, k, order.update_height(k, current_nonce)); } else { + trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); self.by_hash.remove(&order.hash); } } @@ -488,13 +510,11 @@ impl TransactionQueue { /// /// It ignores transactions that has already been imported (same `hash`) and replaces the transaction /// iff `(address, nonce)` is the same but `gas_price` is higher. - fn import_tx(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) - where T: Fn(&Address) -> U256 { - + fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) { if self.by_hash.get(&tx.hash()).is_some() { // Transaction is already imported. - trace!(target: "sync", "Dropping already imported transaction with hash: {:?}", tx.hash()); + trace!(target: "miner", "Dropping already imported transaction: {:?}", tx.hash()); return; } @@ -502,7 +522,6 @@ impl TransactionQueue { let address = tx.sender(); let nonce = tx.nonce(); - let state_nonce = fetch_nonce(&address); let next_nonce = self.last_nonces .get(&address) .cloned() @@ -516,7 +535,7 @@ impl TransactionQueue { return; } else if nonce < state_nonce { // Droping transaction - trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); + trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce); return; } @@ -525,6 +544,8 @@ impl TransactionQueue { // But maybe there are some more items waiting in future? self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); self.current.enforce_limit(&mut self.by_hash); + + trace!(target: "miner", "status: {:?}", self.status()); } /// Replaces transaction in given set (could be `future` or `current`). @@ -583,8 +604,11 @@ mod test { new_unsigned_tx(U256::from(123)).sign(&keypair.secret()) } - fn default_nonce(_address: &Address) -> U256 { - U256::from(123) + fn default_nonce(_address: &Address) -> AccountDetails { + AccountDetails { + nonce: U256::from(123), + balance: !U256::zero() + } } fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) { @@ -953,7 +977,8 @@ mod test { #[test] fn should_not_move_to_future_if_state_nonce_is_higher() { // given - let next_nonce = |a: &Address| default_nonce(a) + U256::one(); + let next_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::one(), balance: + !U256::zero() }; let mut txq = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(1)); let tx3 = new_tx(); @@ -1028,8 +1053,10 @@ mod test { #[test] fn should_recalculate_height_when_removing_from_future() { // given - let previous_nonce = |a: &Address| default_nonce(a) - U256::one(); - let next_nonce = |a: &Address| default_nonce(a) + U256::one(); + let previous_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance: + !U256::zero() }; + let next_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::one(), balance: + !U256::zero() }; let mut txq = TransactionQueue::new(); let (tx1, tx2) = new_txs(U256::one()); txq.add(tx1.clone(), &previous_nonce).unwrap(); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index fda391304..04b25d5b2 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -19,7 +19,7 @@ use std::collections::HashSet; use std::sync::{Arc, Weak, Mutex}; use std::ops::Deref; use ethsync::{SyncProvider, SyncState}; -use ethminer::{MinerService}; +use ethminer::{MinerService, AccountDetails}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; @@ -370,7 +370,10 @@ impl Eth for EthClient let signed_transaction = transaction.sign(&secret); let hash = signed_transaction.hash(); - let import = miner.import_transactions(vec![signed_transaction], |a: &Address| client.nonce(a)); + let import = miner.import_transactions(vec![signed_transaction], |a: &Address| AccountDetails { + nonce: client.nonce(a), + balance: client.balance(a) + }); match import { Ok(_) => to_value(&hash), Err(e) => { diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 0cddf2a1e..b2aebb29c 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -20,7 +20,7 @@ use ethcore::error::Error; use ethcore::client::BlockChainClient; use ethcore::block::ClosedBlock; use ethcore::transaction::SignedTransaction; -use ethminer::{MinerService, MinerStatus}; +use ethminer::{MinerService, MinerStatus, AccountDetails}; pub struct TestMinerService; @@ -30,7 +30,8 @@ impl MinerService for TestMinerService { fn status(&self) -> MinerStatus { unimplemented!(); } /// Imports transactions to transaction queue. - fn import_transactions(&self, _transactions: Vec, _fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256 { unimplemented!(); } + fn import_transactions(&self, _transactions: Vec, _fetch_account: T) -> Result<(), Error> + where T: Fn(&Address) -> AccountDetails { unimplemented!(); } /// Returns hashes of transactions currently in pending fn pending_transactions_hashes(&self) -> Vec { unimplemented!(); } @@ -50,4 +51,4 @@ impl MinerService for TestMinerService { /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { unimplemented!(); } -} \ No newline at end of file +} diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 8f0194289..4f8001ce7 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -38,7 +38,7 @@ use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::transaction::SignedTransaction; use ethcore::block::Block; -use ethminer::{Miner, MinerService}; +use ethminer::{Miner, MinerService, AccountDetails}; use io::SyncIo; use time; use super::SyncConfig; @@ -940,8 +940,11 @@ impl ChainSync { transactions.push(tx); } let chain = io.chain(); - let fetch_nonce = |a: &Address| chain.nonce(a); - let _ = self.miner.import_transactions(transactions, fetch_nonce); + let fetch_account = |a: &Address| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a) + }; + let _ = self.miner.import_transactions(transactions, fetch_account); Ok(()) } From d54c95da9d3cae135a43316c9a62f9bf9f81beb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 16 Mar 2016 10:48:31 +0100 Subject: [PATCH 642/753] Removing unused import --- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index b2aebb29c..7a1ed3809 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::{Address, H256, U256, Bytes}; +use util::{Address, H256, Bytes}; use util::standard::*; use ethcore::error::Error; use ethcore::client::BlockChainClient; From 8741a85443ff6a131cab4bf45af3c941f370e483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 16 Mar 2016 16:47:36 +0100 Subject: [PATCH 643/753] Fixing build --- miner/src/transaction_queue.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index ca4a269ae..abd862a02 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -777,8 +777,10 @@ mod test { #[test] fn should_correctly_update_futures_when_removing() { // given - let prev_nonce = |a: &Address| default_nonce(a) - U256::one(); - let next2_nonce = |a: &Address| default_nonce(a) + U256::from(2); + let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance: + !U256::zero() }; + let next2_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::from(2), balance: + !U256::zero() }; let mut txq = TransactionQueue::new(); @@ -923,7 +925,7 @@ mod test { let mut txq = TransactionQueue::new(); let tx = new_tx(); let last_nonce = tx.nonce + U256::one(); - let fetch_last_nonce = |_a: &Address| last_nonce; + let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() }; // when txq.add(tx, &fetch_last_nonce).unwrap(); @@ -937,7 +939,8 @@ mod test { #[test] fn should_not_insert_same_transaction_twice() { // given - let nonce = |a: &Address| default_nonce(a) + U256::one(); + let nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce + U256::one(), + balance: !U256::zero() }; let mut txq = TransactionQueue::new(); let (_tx1, tx2) = new_txs(U256::from(1)); txq.add(tx2.clone(), &default_nonce).unwrap(); @@ -977,7 +980,7 @@ mod test { #[test] fn should_not_move_to_future_if_state_nonce_is_higher() { // given - let next_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::one(), balance: + let next_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce + U256::one(), balance: !U256::zero() }; let mut txq = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(1)); From 0925968840d3d8ed027587c10ae0fdca253c250f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 16 Mar 2016 17:17:49 +0100 Subject: [PATCH 644/753] Adding test --- miner/src/transaction_queue.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index abd862a02..480d6550a 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -34,7 +34,7 @@ //! use util::crypto::KeyPair; //! use util::hash::Address; //! use util::numbers::{Uint, U256}; -//! use ethminer::TransactionQueue; +//! use ethminer::{TransactionQueue, AccountDetails}; //! use ethcore::transaction::*; //! use rustc_serialize::hex::FromHex; //! @@ -47,7 +47,10 @@ //! //! let st1 = t1.sign(&key.secret()); //! let st2 = t2.sign(&key.secret()); -//! let default_nonce = |_a: &Address| U256::from(10); +//! let default_nonce = |_a: &Address| AccountDetails { +//! nonce: U256::from(10), +//! balance: U256::from(10_000), +//! }; //! //! let mut txq = TransactionQueue::new(); //! txq.add(st2.clone(), &default_nonce); @@ -677,6 +680,25 @@ mod test { assert_eq!(stats.pending, 1); } + #[test] + fn should_drop_transactions_from_senders_without_balance() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + let account = |a: &Address| AccountDetails { + nonce: default_nonce(a).nonce, + balance: U256::one() + }; + + // when + txq.add(tx, &account).unwrap_err(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + #[test] fn should_not_import_transaction_below_min_gas_price_threshold() { // given From b9584b7ec9c028057ca3008ea421d9f419c00e0a Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 16 Mar 2016 18:25:32 +0100 Subject: [PATCH 645/753] restart sync on getting old unknown header --- sync/src/chain.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 8f0194289..4f6c2100a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -402,6 +402,12 @@ impl ChainSync { debug!(target: "sync", "Mismatched block header {}", number + 1); self.remove_downloaded_blocks(number + 1); } + if self.have_common_block && number < self.current_base_block() + 1 { + // unkown header + debug!(target: "sync", "Old block header {:?} ({}) is unknown, restarting sync", hash, number); + self.restart(io); + return Ok(()); + } } let hdr = Header { data: try!(r.at(i)).as_raw().to_vec(), From 5cd3eaa1112464860f9da357ee6103befaf8581e Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 17 Mar 2016 09:54:05 +0100 Subject: [PATCH 646/753] Update install-parity.sh --- install-parity.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-parity.sh b/install-parity.sh index 439700306..74387ca7f 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/beta-0.9/parity_linux_0.9.0-0_amd64.deb +PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/v1.0.0-rc1/parity_linux_1.0.0.rc1-0_amd64.deb function run_installer() From 81c36499ea8bd8bde112de40100793efabc08ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 10:20:35 +0100 Subject: [PATCH 647/753] Fixing sync test --- sync/src/chain.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 8d392dc1c..0af6008f2 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1301,6 +1301,7 @@ mod tests { use ::SyncConfig; use util::*; use super::{PeerInfo, PeerAsking}; + use ethcore::views::BlockView; use ethcore::header::*; use ethcore::client::*; use ethminer::{Miner, MinerService}; @@ -1631,6 +1632,13 @@ mod tests { let good_blocks = vec![client.block_hash_delta_minus(2)]; let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + // Add some balance to clients + for h in vec![good_blocks[0], retracted_blocks[0]] { + let block = client.block(BlockId::Hash(h)).unwrap(); + let view = BlockView::new(&block); + client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(10_000)); + } + let mut queue = VecDeque::new(); let mut io = TestIo::new(&mut client, &mut queue, None); From 95dda4aa68ac87c0320a551df7b08c069848ab27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 10:23:09 +0100 Subject: [PATCH 648/753] Full transaction cost --- miner/src/transaction_queue.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 480d6550a..1842f5f35 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -343,14 +343,16 @@ impl TransactionQueue { })); } + let vtx = try!(VerifiedTransaction::new(tx)); let account = fetch_account(&vtx.sender()); - if account.balance < vtx.transaction.value { + let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas; + if account.balance < cost { trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})", - vtx.hash(), account.balance, vtx.transaction.value); + vtx.hash(), account.balance, cost); return Err(Error::Transaction(TransactionError::InsufficientBalance { - cost: vtx.transaction.value, + cost: cost, balance: account.balance })); } From 884f2dd873d8a7703dcf959d4c87d39f3dfb6ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 11:19:12 +0100 Subject: [PATCH 649/753] Returning number of transactions pending in block not queue --- miner/src/lib.rs | 2 ++ miner/src/miner.rs | 4 +++- rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/tests/eth.rs | 14 ++++++++++++++ rpc/src/v1/tests/helpers/miner_service.rs | 10 ++++++++-- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index a431bd44e..9d2635bef 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -108,4 +108,6 @@ pub struct MinerStatus { pub transaction_queue_pending: usize, /// Number of transactions in queue with state `future` (not yet ready to be included in block) pub transaction_queue_future: usize, + /// Number of transactions included in currently mined block + pub block_pending: usize, } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 6d5b3086e..d9fb0a271 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -22,7 +22,7 @@ use std::sync::atomic::AtomicBool; use util::{H256, U256, Address, Bytes, Uint}; use ethcore::views::{BlockView}; use ethcore::client::{BlockChainClient, BlockId}; -use ethcore::block::{ClosedBlock}; +use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::error::{Error}; use ethcore::transaction::SignedTransaction; use super::{MinerService, MinerStatus, TransactionQueue}; @@ -104,9 +104,11 @@ impl MinerService for Miner { fn status(&self) -> MinerStatus { let status = self.transaction_queue.lock().unwrap().status(); + let block = self.sealing_block.lock().unwrap(); MinerStatus { transaction_queue_pending: status.pending, transaction_queue_future: status.future, + block_pending: block.as_ref().map_or(0, |b| b.transactions().len()), } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index fda391304..0f9582955 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -236,7 +236,7 @@ impl Eth for EthClient fn block_transaction_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { - BlockNumber::Pending => to_value(&U256::from(take_weak!(self.miner).status().transaction_queue_pending)), + BlockNumber::Pending => to_value(&U256::from(take_weak!(self.miner).status().block_pending)), _ => to_value(&take_weak!(self.client).block(block_number.into()) .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count()))) }) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 6bc929709..2fe39ed63 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -242,6 +242,20 @@ fn rpc_eth_transaction_count_by_number() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +fn rpc_eth_transaction_count_by_number_pending() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": ["pending"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x01","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + + #[test] fn rpc_eth_uncle_count_by_block_hash() { let request = r#"{ diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 0cddf2a1e..3afaa3674 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -27,7 +27,13 @@ pub struct TestMinerService; impl MinerService for TestMinerService { /// Returns miner's status. - fn status(&self) -> MinerStatus { unimplemented!(); } + fn status(&self) -> MinerStatus { + MinerStatus { + transaction_queue_pending: 0, + transaction_queue_future: 0, + block_pending: 1 + } + } /// Imports transactions to transaction queue. fn import_transactions(&self, _transactions: Vec, _fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256 { unimplemented!(); } @@ -50,4 +56,4 @@ impl MinerService for TestMinerService { /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { unimplemented!(); } -} \ No newline at end of file +} From 4050462ad4e7b24846965c384dad8e78bb2ad3e6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 17 Mar 2016 11:23:30 +0100 Subject: [PATCH 650/753] Update sync_provider.rs --- rpc/src/v1/tests/helpers/sync_provider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index bfbfad44b..5b4b5b099 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -40,7 +40,7 @@ impl TestSyncProvider { num_peers: config.num_peers, num_active_peers: 0, mem_used: 0, - }) + }), } } } From 0e7778a7b79be72d25c57fce129098abfa68af44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 11:27:38 +0100 Subject: [PATCH 651/753] Increasing balance in tests --- sync/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 0af6008f2..06fbcd5d1 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -403,7 +403,7 @@ impl ChainSync { self.remove_downloaded_blocks(number + 1); } if self.have_common_block && number < self.current_base_block() + 1 { - // unkown header + // unkown header debug!(target: "sync", "Old block header {:?} ({}) is unknown, restarting sync", hash, number); self.restart(io); return Ok(()); @@ -1636,7 +1636,7 @@ mod tests { for h in vec![good_blocks[0], retracted_blocks[0]] { let block = client.block(BlockId::Hash(h)).unwrap(); let view = BlockView::new(&block); - client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(10_000)); + client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000)); } let mut queue = VecDeque::new(); From b1557b547b04abbef6ce8d116c80814c6d710540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 11:47:41 +0100 Subject: [PATCH 652/753] Reverting check if block queue is empty --- ethcore/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 6857416d3..caa92db97 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -317,7 +317,7 @@ impl Client where V: Verifier { } { - if !imported_blocks.is_empty() { + if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { let (enacted, retracted) = self.calculate_enacted_retracted(import_results); io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { imported: imported_blocks, From bc04e0c71304237a2f5aba9c59cb14923169e302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 11:49:56 +0100 Subject: [PATCH 653/753] Adding missing commas --- rpc/src/v1/impls/eth.rs | 2 +- sync/src/chain.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 04b25d5b2..b566dd848 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -372,7 +372,7 @@ impl Eth for EthClient let import = miner.import_transactions(vec![signed_transaction], |a: &Address| AccountDetails { nonce: client.nonce(a), - balance: client.balance(a) + balance: client.balance(a), }); match import { Ok(_) => to_value(&hash), diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 06fbcd5d1..492481722 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -948,7 +948,7 @@ impl ChainSync { let chain = io.chain(); let fetch_account = |a: &Address| AccountDetails { nonce: chain.nonce(a), - balance: chain.balance(a) + balance: chain.balance(a), }; let _ = self.miner.import_transactions(transactions, fetch_account); Ok(()) From f92a0c8df296c83c69d7a78ba0502153f79744e0 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 17 Mar 2016 11:50:31 +0100 Subject: [PATCH 654/753] rpctest executable --- Cargo.lock | 1 + Cargo.toml | 5 ++ json/src/blockchain/block.rs | 7 +++ json/src/blockchain/blockchain.rs | 12 +++++ json/src/blockchain/mod.rs | 8 ++++ json/src/blockchain/test.rs | 1 + json/src/bytes.rs | 2 +- parity/rpctest.rs | 80 +++++++++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 parity/rpctest.rs diff --git a/Cargo.lock b/Cargo.lock index 79ca26582..1a701042e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,7 @@ dependencies = [ "rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index fd1d16cff..d00f1ff60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } ethjson = { path = "json" } +serde_json = "0.7.0" [features] default = ["rpc"] @@ -40,6 +41,10 @@ travis-nightly = ["ethcore/json-tests", "dev"] path = "parity/main.rs" name = "parity" +[[bin]] +path = "parity/rpctest.rs" +name = "rpctest" + [profile.release] debug = false lto = false diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs index ed297077c..190102ae5 100644 --- a/json/src/blockchain/block.rs +++ b/json/src/blockchain/block.rs @@ -31,6 +31,13 @@ pub struct Block { uncles: Vec
, } +impl Block { + /// Returns block rlp. + pub fn rlp(&self) -> Vec { + self.rlp.clone().into() + } +} + #[cfg(test)] mod tests { use serde_json; diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index f6b1259ca..8c67799e1 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -35,6 +35,18 @@ pub struct BlockChain { pre_state: State, } +impl BlockChain { + /// Returns genesis block rlp. + pub fn genesis_rlp(&self) -> Vec { + self.genesis_rlp.clone().into() + } + + /// Returns blocks rlp. + pub fn blocks_rlp(&self) -> Vec> { + self.blocks.iter().map(|block| block.rlp()).collect() + } +} + #[cfg(test)] mod tests { use serde_json; diff --git a/json/src/blockchain/mod.rs b/json/src/blockchain/mod.rs index 046b2e534..727469ea2 100644 --- a/json/src/blockchain/mod.rs +++ b/json/src/blockchain/mod.rs @@ -23,3 +23,11 @@ pub mod header; pub mod state; pub mod transaction; pub mod test; + +pub use self::account::Account; +pub use self::block::Block; +pub use self::blockchain::BlockChain; +pub use self::header::Header; +pub use self::state::State; +pub use self::test::Test; +pub use self::transaction::Transaction; diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs index 6097a60e6..6f48a8bc6 100644 --- a/json/src/blockchain/test.rs +++ b/json/src/blockchain/test.rs @@ -21,6 +21,7 @@ use std::ops::Deref; use blockchain::blockchain::BlockChain; /// Blockchain test deserializer. +#[derive(Debug, PartialEq, Deserialize)] pub struct Test(BTreeMap); impl Deref for Test { diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 28b7636d4..061795b40 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -21,7 +21,7 @@ use serde::{Deserialize, Deserializer, Error}; use serde::de::Visitor; /// Lenient bytes json deserialization for test json files. -#[derive(Default, Debug, PartialEq)] +#[derive(Default, Debug, PartialEq, Clone)] pub struct Bytes(Vec); impl Into> for Bytes { diff --git a/parity/rpctest.rs b/parity/rpctest.rs new file mode 100644 index 000000000..182f6dfed --- /dev/null +++ b/parity/rpctest.rs @@ -0,0 +1,80 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate docopt; +extern crate rustc_serialize; +extern crate serde_json; +extern crate ethjson; + +use std::process; +use std::fs::File; +use std::path::Path; +use docopt::Docopt; + +const USAGE: &'static str = r#" +Parity rpctest client. + By Wood/Paronyan/Kotewicz/Drwięga/Volf. + Copyright 2015, 2016 Ethcore (UK) Limited + +Usage: + parity --json --name +"#; + +#[derive(Debug, RustcDecodable)] +struct Args { + arg_test_file: String, + arg_test_name: String, +} + +struct Configuration { + args: Args, +} + +impl Configuration { + fn parse() -> Self { + Configuration { + args: Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()) + } + } + + fn execute(&self) { + println!("file path: {:?}", self.args.arg_test_file); + println!("test name: {:?}", self.args.arg_test_name); + + let path = Path::new(&self.args.arg_test_file); + let file = File::open(path).unwrap_or_else(|_| { + println!("Cannot open file."); + process::exit(1); + }); + + let tests: ethjson::blockchain::Test = serde_json::from_reader(file).unwrap_or_else(|_| { + println!("Invalid json file."); + process::exit(2); + }); + + let blockchain = tests.get(&self.args.arg_test_name).unwrap_or_else(|| { + println!("Invalid test name."); + process::exit(3); + }); + + + + } +} + +fn main() { + Configuration::parse().execute(); +} From 03ca9d2c0662c706d1b37ce0d1e71fa03ccfcc12 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 17 Mar 2016 12:17:53 +0100 Subject: [PATCH 655/753] adding message from client to sync and disabling sending transactions to the queue while syncing --- ethcore/src/client/client.rs | 6 ++++ ethcore/src/service.rs | 2 ++ rpc/src/v1/impls/eth.rs | 2 +- sync/src/chain.rs | 58 ++++++++++++++++++++++++++++++++++-- sync/src/lib.rs | 3 ++ 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index caa92db97..d8c48e696 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -334,6 +334,12 @@ impl Client where V: Verifier { } } + { + if self.queue_info().is_empty() { + io.send(NetworkIoMessage::User(SyncMessage::BlockQueueEmpty)).expect("error sending message to sync module"); + } + } + imported } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index bcfe7724f..1c2385934 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -40,6 +40,8 @@ pub enum SyncMessage { NewChainHead, /// A block is ready BlockVerified, + /// blocks queue is empty + BlockQueueEmpty, } /// IO Message type used for Network service diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 520b37045..b0e31ba97 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -151,7 +151,7 @@ impl Eth for EthClient Params::None => { let status = take_weak!(self.sync).status(); let res = match status.state { - SyncState::NotSynced | SyncState::Idle => SyncStatus::None, + SyncState::NotSynced | SyncState::Idle | SyncState::FullySynced => SyncStatus::None, SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks => SyncStatus::Info(SyncInfo { starting_block: U256::from(status.start_block_number), current_block: U256::from(take_weak!(self.client).chain_info().best_block_number), diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 363597d40..5af299b34 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -116,6 +116,8 @@ pub enum SyncState { Blocks, /// Downloading blocks learned from NewHashes packet NewBlocks, + /// Once has an event that client finished processing new blocks + FullySynced, } /// Syncing status and statistics @@ -930,6 +932,11 @@ impl ChainSync { } /// Called when peer sends us new transactions fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { + // accepting transactions once only fully synced + if self.state != SyncState::FullySynced { + return Ok(()); + } + let item_count = r.item_count(); trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count); @@ -1272,15 +1279,31 @@ impl ChainSync { /// called when block is imported to chain, updates transactions queue and propagates the blocks pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { - // Notify miner - self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); + if self.state == SyncState::FullySynced { + // Notify miner + self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); + } // Propagate latests blocks self.propagate_latest_blocks(io); // TODO [todr] propagate transactions? } pub fn chain_new_head(&mut self, io: &mut SyncIo) { - self.miner.prepare_sealing(io.chain()); + if self.state == SyncState::FullySynced { + self.miner.prepare_sealing(io.chain()); + } + } + + // called once has nothing to download and client reports that all that downloaded is imported + pub fn set_fully_synced(&mut self) { + self.state = SyncState::FullySynced; + } + + // handles event from client about empty blow_queue + pub fn client_block_queue_empty(&mut self) { + if self.state == SyncState::Idle { + self.set_fully_synced(); + } } } @@ -1616,6 +1639,7 @@ mod tests { client.add_blocks(1, EachBlockWith::UncleAndTransaction); client.add_blocks(1, EachBlockWith::Transaction); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); + sync.state = SyncState::FullySynced; let good_blocks = vec![client.block_hash_delta_minus(2)]; let retracted_blocks = vec![client.block_hash_delta_minus(1)]; @@ -1635,6 +1659,34 @@ mod tests { assert_eq!(status.transaction_queue_future, 0); } + #[test] + fn should_not_add_transactions_to_queue_if_not_synced() { + // given + let mut client = TestBlockChainClient::new(); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); + sync.state = SyncState::Idle; + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + + let mut queue = VecDeque::new(); + let mut io = TestIo::new(&mut client, &mut queue, None); + + // when + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); + assert_eq!(sync.miner.status().transaction_queue_future, 0); + assert_eq!(sync.miner.status().transaction_queue_pending, 0); + sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); + + // then + let status = sync.miner.status(); + assert_eq!(status.transaction_queue_pending, 0); + assert_eq!(status.transaction_queue_future, 0); + } + #[test] fn returns_requested_block_headers() { let mut client = TestBlockChainClient::new(); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 1c87da2de..d78ac3b89 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -173,6 +173,9 @@ impl NetworkProtocolHandler for EthSync { SyncMessage::NewChainHead => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); self.sync.write().unwrap().chain_new_head(&mut sync_io); + }, + SyncMessage::BlockQueueEmpty => { + self.sync.write().unwrap().client_block_queue_empty(); } _ => {/* Ignore other messages */}, } From 7247f9e27f9eb59f2d11a666de3e9f1afed90a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 12:23:15 +0100 Subject: [PATCH 656/753] Fixing doctest --- miner/src/transaction_queue.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 1842f5f35..a1fc20b0f 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -49,12 +49,12 @@ //! let st2 = t2.sign(&key.secret()); //! let default_nonce = |_a: &Address| AccountDetails { //! nonce: U256::from(10), -//! balance: U256::from(10_000), +//! balance: U256::from(1_000_000), //! }; //! //! let mut txq = TransactionQueue::new(); -//! txq.add(st2.clone(), &default_nonce); -//! txq.add(st1.clone(), &default_nonce); +//! txq.add(st2.clone(), &default_nonce).unwrap(); +//! txq.add(st1.clone(), &default_nonce).unwrap(); //! //! // Check status //! assert_eq!(txq.status().pending, 2); From c382fa7eaba8359838a5a854479362254e749f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 12:17:20 +0100 Subject: [PATCH 657/753] Removing invalid transactions from queue --- ethcore/src/client/client.rs | 31 ++++++++++++++++++++++++++----- ethcore/src/client/mod.rs | 4 +++- ethcore/src/client/test_client.rs | 2 +- ethcore/src/tests/client.rs | 2 +- miner/src/miner.rs | 15 ++++++++++++++- 5 files changed, 45 insertions(+), 9 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index caa92db97..7818fcdc8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -391,7 +391,8 @@ impl BlockChainClient for Client where V: Verifier { } // TODO [todr] Should be moved to miner crate eventually. - fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> Option { + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) + -> Option<(ClosedBlock, HashSet)> { let engine = self.engine.deref().deref(); let h = self.chain.best_block_hash(); @@ -417,21 +418,41 @@ impl BlockChainClient for Client where V: Verifier { // Add transactions let block_number = b.block().header().number(); + let gas_limit = *b.block().header().gas_limit(); + let mut gas_left = gas_limit; + let mut invalid_transactions = HashSet::new(); + for tx in transactions { + let hash = tx.hash(); + let gas = tx.gas; + // TODO [todr] It seems that calculating gas_left here doesn't really look nice. After moving this function + // to miner crate we should consider rewriting this logic in some better way. + if gas > gas_left { + trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); + continue; + } + let import = b.push_transaction(tx, None); - if let Err(e) = import { - trace!("Error adding transaction to block: number={}. Error: {:?}", block_number, e); + match import { + Err(e) => { + trace!(target: "miner", "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", + block_number, hash, e); + invalid_transactions.insert(hash); + }, + Ok(receipt) => { + gas_left = gas_limit - receipt.gas_used; + } } } // And close let b = b.close(); - trace!("Sealing: number={}, hash={}, diff={}", + trace!(target: "miner", "Sealing: number={}, hash={}, diff={}", b.block().header().number(), b.hash(), b.block().header().difficulty() ); - Some(b) + Some((b, invalid_transactions)) } fn block_header(&self, id: BlockId) -> Option { diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 88e07d0b1..198e918f7 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -26,6 +26,7 @@ pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; pub use self::ids::{BlockId, TransactionId}; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; +use std::collections::HashSet; use util::bytes::Bytes; use util::hash::{Address, H256, H2048}; use util::numbers::U256; @@ -110,7 +111,8 @@ pub trait BlockChainClient : Sync + Send { // TODO [todr] Should be moved to miner crate eventually. /// Returns ClosedBlock prepared for sealing. - fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> Option; + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) + -> Option<(ClosedBlock, HashSet)>; // TODO [todr] Should be moved to miner crate eventually. /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 83511b1cc..e351011f2 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -217,7 +217,7 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> Option { + fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> Option<(ClosedBlock, HashSet)> { unimplemented!() } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d9fae0527..64a2222b1 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -144,7 +144,7 @@ fn can_mine() { let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let client = client_result.reference(); - let b = client.prepare_sealing(Address::default(), x!(31415926), vec![], vec![]).unwrap(); + let b = client.prepare_sealing(Address::default(), x!(31415926), vec![], vec![]).unwrap().0; assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); assert!(client.try_seal(b, vec![]).is_ok()); diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 6d5b3086e..776cf7c83 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -132,7 +132,20 @@ impl MinerService for Miner { self.extra_data(), transactions, ); - *self.sealing_block.lock().unwrap() = b; + + match b { + None => { + *self.sealing_block.lock().unwrap() = None + }, + Some((block, invalid_transactions)) => { + let mut queue = self.transaction_queue.lock().unwrap(); + queue.remove_all( + &invalid_transactions.into_iter().collect::>(), + |a: &Address| chain.nonce(a) + ); + *self.sealing_block.lock().unwrap() = Some(block) + } + } } fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { From b684bc9ba01d292bf5bfdc4b13fe0eb95525ab0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 12:47:31 +0100 Subject: [PATCH 658/753] Updating sealing when new transactions are received --- miner/src/lib.rs | 2 +- miner/src/miner.rs | 37 +++++++++++++---------- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- sync/src/chain.rs | 9 ++++-- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index a431bd44e..d6310eb8a 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -92,7 +92,7 @@ pub trait MinerService : Send + Sync { fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); /// New chain head event. Restart mining operation. - fn prepare_sealing(&self, chain: &BlockChainClient); + fn update_sealing(&self, chain: &BlockChainClient); /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex>; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 6d5b3086e..d177d81ee 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -93,13 +93,28 @@ impl Miner { pub fn set_minimal_gas_price(&self, min_gas_price: U256) { self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price); } + + /// Prepares new block for sealing including top transactions from queue. + pub fn prepare_sealing(&self, chain: &BlockChainClient) { + let no_of_transactions = 128; + // TODO: should select transactions orm queue according to gas limit of block. + let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); + + let b = chain.prepare_sealing( + self.author(), + self.gas_floor_target(), + self.extra_data(), + transactions, + ); + *self.sealing_block.lock().unwrap() = b; + } } impl MinerService for Miner { fn clear_and_reset(&self, chain: &BlockChainClient) { self.transaction_queue.lock().unwrap().clear(); - self.prepare_sealing(chain); + self.update_sealing(chain); } fn status(&self) -> MinerStatus { @@ -121,18 +136,10 @@ impl MinerService for Miner { transaction_queue.pending_hashes() } - fn prepare_sealing(&self, chain: &BlockChainClient) { - let no_of_transactions = 128; - // TODO: should select transactions orm queue according to gas limit of block. - let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); - - let b = chain.prepare_sealing( - self.author(), - self.gas_floor_target(), - self.extra_data(), - transactions, - ); - *self.sealing_block.lock().unwrap() = b; + fn update_sealing(&self, chain: &BlockChainClient) { + if self.sealing_enabled.load(atomic::Ordering::Relaxed) { + self.prepare_sealing(chain); + } } fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { @@ -199,8 +206,6 @@ impl MinerService for Miner { }); } - if self.sealing_enabled.load(atomic::Ordering::Relaxed) { - self.prepare_sealing(chain); - } + self.update_sealing(chain); } } diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 3a60bd136..9f38b374b 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -54,7 +54,7 @@ impl MinerService for TestMinerService { fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); } /// New chain head event. Restart mining operation. - fn prepare_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } + fn update_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex> { diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 4f6c2100a..c87dc9535 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -403,7 +403,7 @@ impl ChainSync { self.remove_downloaded_blocks(number + 1); } if self.have_common_block && number < self.current_base_block() + 1 { - // unkown header + // unkown header debug!(target: "sync", "Old block header {:?} ({}) is unknown, restarting sync", hash, number); self.restart(io); return Ok(()); @@ -947,7 +947,10 @@ impl ChainSync { } let chain = io.chain(); let fetch_nonce = |a: &Address| chain.nonce(a); - let _ = self.miner.import_transactions(transactions, fetch_nonce); + let res = self.miner.import_transactions(transactions, fetch_nonce); + if res.is_ok() { + self.miner.update_sealing(io.chain()); + } Ok(()) } @@ -1287,7 +1290,7 @@ impl ChainSync { } pub fn chain_new_head(&mut self, io: &mut SyncIo) { - self.miner.prepare_sealing(io.chain()); + self.miner.update_sealing(io.chain()); } } From e1c3ab18462096672de67fd19c5f79106abdd9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 11:19:12 +0100 Subject: [PATCH 659/753] Renaming status fields to something more descriptive. --- miner/src/lib.rs | 8 ++++---- miner/src/miner.rs | 6 +++--- rpc/src/v1/impls/eth.rs | 4 +++- rpc/src/v1/tests/helpers/miner_service.rs | 6 +++--- sync/src/chain.rs | 10 +++++----- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 9d2635bef..5821c9815 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -42,7 +42,7 @@ //! //! let miner: Miner = Miner::default(); //! // get status -//! assert_eq!(miner.status().transaction_queue_pending, 0); +//! assert_eq!(miner.status().transactions_in_pending_queue, 0); //! //! // Check block for sealing //! miner.prepare_sealing(client.deref()); @@ -105,9 +105,9 @@ pub trait MinerService : Send + Sync { /// Mining status pub struct MinerStatus { /// Number of transactions in queue with state `pending` (ready to be included in block) - pub transaction_queue_pending: usize, + pub transactions_in_pending_queue: usize, /// Number of transactions in queue with state `future` (not yet ready to be included in block) - pub transaction_queue_future: usize, + pub transactions_in_future_queue: usize, /// Number of transactions included in currently mined block - pub block_pending: usize, + pub transactions_in_pending_block: usize, } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index d9fb0a271..ccf45f61a 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -106,9 +106,9 @@ impl MinerService for Miner { let status = self.transaction_queue.lock().unwrap().status(); let block = self.sealing_block.lock().unwrap(); MinerStatus { - transaction_queue_pending: status.pending, - transaction_queue_future: status.future, - block_pending: block.as_ref().map_or(0, |b| b.transactions().len()), + transactions_in_pending_queue: status.pending, + transactions_in_future_queue: status.future, + transactions_in_pending_block: block.as_ref().map_or(0, |b| b.transactions().len()), } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 0f9582955..c8306c2c9 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -236,7 +236,9 @@ impl Eth for EthClient fn block_transaction_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { - BlockNumber::Pending => to_value(&U256::from(take_weak!(self.miner).status().block_pending)), + BlockNumber::Pending =>to_value( + &U256::from(take_weak!(self.miner).status().transactions_in_pending_block) + ), _ => to_value(&take_weak!(self.client).block(block_number.into()) .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count()))) }) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 3afaa3674..776a04f75 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -29,9 +29,9 @@ impl MinerService for TestMinerService { /// Returns miner's status. fn status(&self) -> MinerStatus { MinerStatus { - transaction_queue_pending: 0, - transaction_queue_future: 0, - block_pending: 1 + transactions_in_pending_queue: 0, + transactions_in_future_queue: 0, + transactions_in_pending_block: 1 } } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 4f6c2100a..206dd5dd2 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -403,7 +403,7 @@ impl ChainSync { self.remove_downloaded_blocks(number + 1); } if self.have_common_block && number < self.current_base_block() + 1 { - // unkown header + // unkown header debug!(target: "sync", "Old block header {:?} ({}) is unknown, restarting sync", hash, number); self.restart(io); return Ok(()); @@ -1633,14 +1633,14 @@ mod tests { // when sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); - assert_eq!(sync.miner.status().transaction_queue_future, 0); - assert_eq!(sync.miner.status().transaction_queue_pending, 1); + assert_eq!(sync.miner.status().transactions_in_future_queue, 0); + assert_eq!(sync.miner.status().transactions_in_pending_queue, 1); sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); // then let status = sync.miner.status(); - assert_eq!(status.transaction_queue_pending, 1); - assert_eq!(status.transaction_queue_future, 0); + assert_eq!(status.transactions_in_pending_queue, 1); + assert_eq!(status.transactions_in_future_queue, 0); } #[test] From 83f5cc6aa69bdc262e76235460c509d3fd3ef488 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 17 Mar 2016 13:14:06 +0100 Subject: [PATCH 660/753] adding helper can_sync --- sync/src/chain.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 8697c94a7..f7a03a7bd 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -405,7 +405,7 @@ impl ChainSync { self.remove_downloaded_blocks(number + 1); } if self.have_common_block && number < self.current_base_block() + 1 { - // unkown header + // unkown header debug!(target: "sync", "Old block header {:?} ({}) is unknown, restarting sync", hash, number); self.restart(io); return Ok(()); @@ -627,6 +627,13 @@ impl ChainSync { self.state = SyncState::Waiting; } + fn can_sync(&self) -> bool { + match self.state { + SyncState::Idle | SyncState::NotSynced | SyncState::FullySynced => true, + _ => false + } + } + /// Find something to do for a peer. Called for a new peer or when a peer is done with it's task. fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) { let (peer_latest, peer_difficulty) = { @@ -646,7 +653,7 @@ impl ChainSync { if force || peer_difficulty > syncing_difficulty { // start sync self.syncing_difficulty = peer_difficulty; - if self.state == SyncState::Idle || self.state == SyncState::NotSynced { + if self.can_sync() { self.state = SyncState::Blocks; } trace!(target: "sync", "Starting sync with better chain"); From caedb64ade3b202e47c5c7220cd8639370db6f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 13:18:26 +0100 Subject: [PATCH 661/753] Adding missing space --- rpc/src/v1/impls/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index c8306c2c9..6c434a66b 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -236,7 +236,7 @@ impl Eth for EthClient fn block_transaction_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { - BlockNumber::Pending =>to_value( + BlockNumber::Pending => to_value( &U256::from(take_weak!(self.miner).status().transactions_in_pending_block) ), _ => to_value(&take_weak!(self.client).block(block_number.into()) From 0621da85358e908fc703f75fc4579548adf1c290 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 17 Mar 2016 13:41:11 +0100 Subject: [PATCH 662/753] ethjson spec submodule --- ethcore/res/ethereum/frontier_like_test.json | 2 +- ethcore/res/ethereum/frontier_test.json | 2 +- json/src/hash.rs | 4 + json/src/lib.rs.in | 1 + json/src/spec/account.rs | 44 ++++++++++ json/src/spec/builtin.rs | 47 +++++++++++ json/src/spec/genesis.rs | 67 ++++++++++++++++ json/src/spec/mod.rs | 29 +++++++ json/src/spec/params.rs | 74 +++++++++++++++++ json/src/spec/spec.rs | 84 ++++++++++++++++++++ 10 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 json/src/spec/account.rs create mode 100644 json/src/spec/builtin.rs create mode 100644 json/src/spec/genesis.rs create mode 100644 json/src/spec/mod.rs create mode 100644 json/src/spec/params.rs create mode 100644 json/src/spec/spec.rs diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 3e4108566..ebfbc2383 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -1,5 +1,5 @@ { - "engineName": "Frontier (Test)", + "name": "Frontier (Test)", "engineName": "Ethash", "params": { "accountStartNonce": "0x00", diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index 8ee1cafd9..227ad1bc3 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -1,5 +1,5 @@ { - "engineName": "Frontier (Test)", + "name": "Frontier (Test)", "engineName": "Ethash", "params": { "accountStartNonce": "0x00", diff --git a/json/src/hash.rs b/json/src/hash.rs index 098f2e7a8..bece68011 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -46,6 +46,10 @@ macro_rules! impl_hash { fn visit_str(&mut self, value: &str) -> Result where E: Error { let value = match value.len() { 0 => $inner::from(0), + 2 if value == "0x" => $inner::from(0), + _ if value.starts_with("0x") => try!($inner::from_str(&value[2..]).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })), _ => try!($inner::from_str(value).map_err(|_| { Error::custom(format!("Invalid hex value {}.", value).as_ref()) })) diff --git a/json/src/lib.rs.in b/json/src/lib.rs.in index 6d3437811..0d85ce569 100644 --- a/json/src/lib.rs.in +++ b/json/src/lib.rs.in @@ -23,3 +23,4 @@ pub mod hash; pub mod uint; pub mod bytes; pub mod blockchain; +pub mod spec; diff --git a/json/src/spec/account.rs b/json/src/spec/account.rs new file mode 100644 index 000000000..8c98f89d9 --- /dev/null +++ b/json/src/spec/account.rs @@ -0,0 +1,44 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Spec account deserialization. + +use uint::Uint; +use spec::builtin::Builtin; + +/// Spec account. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Account { + builtin: Option, + balance: Option, + nonce: Option, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::account::Account; + + #[test] + fn account_deserialization() { + let s = r#"{ + "balance": "1", + "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } + }"#; + let _deserialized: Account = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/builtin.rs b/json/src/spec/builtin.rs new file mode 100644 index 000000000..f49367ecb --- /dev/null +++ b/json/src/spec/builtin.rs @@ -0,0 +1,47 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Spec builtin deserialization. + +/// Linear builin options. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Linear { + base: u64, + word: u64, +} + +/// Spec builtin. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Builtin { + name: String, + linear: Linear, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::builtin::Builtin; + + #[test] + fn builtin_deserialization() { + let s = r#"{ + "name": "ecrecover", + "linear": { "base": 3000, "word": 0 } + }"#; + let _deserialized: Builtin = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/genesis.rs b/json/src/spec/genesis.rs new file mode 100644 index 000000000..4c66a9e35 --- /dev/null +++ b/json/src/spec/genesis.rs @@ -0,0 +1,67 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Spec genesis deserialization. + +use uint::Uint; +use hash::{Address, H256}; +use bytes::Bytes; + +/// Spec genesis. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Genesis { + // old seal + nonce: Option, + #[serde(rename="mixHash")] + mix_hash: Option, + + // new seal // TODO: consider moving it to a separate seal structure + #[serde(rename="sealFields")] + seal_fields: Option, + #[serde(rename="sealRlp")] + seal_rlp: Option, + + difficulty: Uint, + author: Address, + timestamp: Uint, + #[serde(rename="parentHash")] + parent_hash: H256, + #[serde(rename="gasLimit")] + gas_limit: Uint, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::genesis::Genesis; + + #[test] + fn genesis_deserialization() { + let s = r#"{ + "nonce": "0x0000000000000042", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x1388", + "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544" + }"#; + let _deserialized: Genesis = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/mod.rs b/json/src/spec/mod.rs new file mode 100644 index 000000000..8783563d1 --- /dev/null +++ b/json/src/spec/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Spec deserialization. + +pub mod account; +pub mod builtin; +pub mod genesis; +pub mod params; +pub mod spec; + +pub use self::account::Account; +pub use self::builtin::Builtin; +pub use self::genesis::Genesis; +pub use self::params::Params; +pub use self::spec::Spec; diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs new file mode 100644 index 000000000..e55f7fc48 --- /dev/null +++ b/json/src/spec/params.rs @@ -0,0 +1,74 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Spec params deserialization. + +use uint::Uint; +use hash::Address; + +/// Spec params. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Params { + #[serde(rename="accountStartNonce")] + account_start_nonce: Uint, + #[serde(rename="frontierCompatibilityModeLimit")] + frontier_compatibility_mode_limit: Uint, + #[serde(rename="maximumExtraDataSize")] + maximum_extra_data_size: Uint, + #[serde(rename="tieBreakingGas")] + tie_breaking_gas: bool, + #[serde(rename="minGasLimit")] + min_gas_limit: Uint, + #[serde(rename="gasLimitBoundDivisor")] + gas_limit_bound_divisor: Uint, + #[serde(rename="minimumDifficulty")] + minimum_difficulty: Uint, + #[serde(rename="difficultyBoundDivisor")] + difficulty_bound_divisor: Uint, + #[serde(rename="durationLimit")] + duration_limit: Uint, + #[serde(rename="blockReward")] + block_reward: Uint, + registrar: Address, + #[serde(rename="networkID")] + network_id: Uint, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::params::Params; + + #[test] + fn params_deserialization() { + let s = r#"{ + "accountStartNonce": "0x00", + "frontierCompatibilityModeLimit": "0x118c30", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", + "networkID" : "0x1" + }"#; + let _deserialized: Params = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs new file mode 100644 index 000000000..79662b19a --- /dev/null +++ b/json/src/spec/spec.rs @@ -0,0 +1,84 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Spec deserialization. + +use std::collections::BTreeMap; +use hash::Address; +use spec::account::Account; +use spec::params::Params; +use spec::genesis::Genesis; + +/// Spec deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Spec { + name: String, + #[serde(rename="engineName")] + engine_name: String, // TODO: consider making it an enum + params: Params, + genesis: Genesis, + accounts: BTreeMap, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::spec::Spec; + + #[test] + fn spec_deserialization() { + let s = r#"{ + "name": "Morden", + "engineName": "Ethash", + "params": { + "accountStartNonce": "0x0100000", + "frontierCompatibilityModeLimit": "0x789b0", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar": "", + "networkID" : "0x2" + }, + "genesis": { + "nonce": "0x00006d6f7264656e", + "difficulty": "0x20000", + "mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x2fefd8" + }, + "nodes": [ + "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } + } + }"#; + let _deserialized: Spec = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} From dec69651fddee226bce347893ad4724183ebacbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 13:41:08 +0100 Subject: [PATCH 663/753] Attempting to add all transactions to mined block --- miner/src/miner.rs | 5 +---- miner/src/transaction_queue.rs | 17 ++++++++--------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 832dc5d02..7bbde6294 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -125,10 +125,7 @@ impl MinerService for Miner { } fn prepare_sealing(&self, chain: &BlockChainClient) { - let no_of_transactions = 128; - // TODO: should select transactions orm queue according to gas limit of block. - let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); - + let transactions = self.transaction_queue.lock().unwrap().top_transactions(); let b = chain.prepare_sealing( self.author(), self.gas_floor_target(), diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index a1fc20b0f..71d845e38 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -59,7 +59,7 @@ //! // Check status //! assert_eq!(txq.status().pending, 2); //! // Check top transactions -//! let top = txq.top_transactions(3); +//! let top = txq.top_transactions(); //! assert_eq!(top.len(), 2); //! assert_eq!(top[0], st1); //! assert_eq!(top[1], st2); @@ -69,7 +69,7 @@ //! txq.remove(&st1.hash(), &default_nonce); //! assert_eq!(txq.status().pending, 0); //! assert_eq!(txq.status().future, 1); -//! assert_eq!(txq.top_transactions(3).len(), 0); +//! assert_eq!(txq.top_transactions().len(), 0); //! } //! ``` //! @@ -459,10 +459,9 @@ impl TransactionQueue { // Will be used when mining merged #[allow(dead_code)] /// Returns top transactions from the queue ordered by priority. - pub fn top_transactions(&self, size: usize) -> Vec { + pub fn top_transactions(&self) -> Vec { self.current.by_priority .iter() - .take(size) .map(|t| self.by_hash.get(&t.hash).expect("Transaction Queue Inconsistency")) .map(|t| t.transaction.clone()) .collect() @@ -754,7 +753,7 @@ mod test { txq.add(tx2.clone(), &default_nonce).unwrap(); // then - let top = txq.top_transactions(5); + let top = txq.top_transactions(); assert_eq!(top[0], tx); assert_eq!(top[1], tx2); assert_eq!(top.len(), 2); @@ -793,7 +792,7 @@ mod test { let stats = txq.status(); assert_eq!(stats.pending, 1); assert_eq!(stats.future, 1); - let top = txq.top_transactions(5); + let top = txq.top_transactions(); assert_eq!(top.len(), 1); assert_eq!(top[0], tx); } @@ -920,7 +919,7 @@ mod test { txq.add(tx2.clone(), &default_nonce).unwrap(); // then - let t = txq.top_transactions(2); + let t = txq.top_transactions(); assert_eq!(txq.status().pending, 1); assert_eq!(t.len(), 1); assert_eq!(t[0], tx); @@ -1044,7 +1043,7 @@ mod test { let stats = txq.status(); assert_eq!(stats.pending, 1); assert_eq!(stats.future, 0); - assert_eq!(txq.top_transactions(1)[0].gas_price, U256::from(200)); + assert_eq!(txq.top_transactions()[0].gas_price, U256::from(200)); } #[test] @@ -1074,7 +1073,7 @@ mod test { let stats = txq.status(); assert_eq!(stats.future, 0); assert_eq!(stats.pending, 2); - assert_eq!(txq.top_transactions(2)[1].gas_price, U256::from(200)); + assert_eq!(txq.top_transactions()[1].gas_price, U256::from(200)); } #[test] From 0f889d42222dd33bd1dad28dfc25bd1b6165601f Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 17 Mar 2016 14:03:53 +0100 Subject: [PATCH 664/753] added genesis method to ethjson blockchain --- json/src/blockchain/blockchain.rs | 16 ++++++++++ json/src/blockchain/header.rs | 49 +++++++++++++++++++++---------- json/src/hash.rs | 2 +- json/src/spec/genesis.rs | 29 +++++++++++------- json/src/uint.rs | 2 +- 5 files changed, 70 insertions(+), 28 deletions(-) diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 8c67799e1..75d321a4d 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -20,6 +20,7 @@ use bytes::Bytes; use blockchain::state::State; use blockchain::header::Header; use blockchain::block::Block; +use spec::Genesis; /// Blockchain deserialization. #[derive(Debug, PartialEq, Deserialize)] @@ -45,6 +46,21 @@ impl BlockChain { pub fn blocks_rlp(&self) -> Vec> { self.blocks.iter().map(|block| block.rlp()).collect() } + + /// Returns spec compatible genesis struct. + pub fn genesis(&self) -> Genesis { + Genesis { + nonce: Some(self.genesis_block.nonce.clone()), + mix_hash: Some(self.genesis_block.mix_hash.clone()), + seal_fields: None, + seal_rlp: None, + difficulty: self.genesis_block.difficulty, + author: self.genesis_block.author.clone(), + timestamp: self.genesis_block.timestamp, + parent_hash: self.genesis_block.parent_hash.clone(), + gas_limit: self.genesis_block.gas_limit, + } + } } #[cfg(test)] diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index e97039213..f4ebee01b 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -23,31 +23,48 @@ use bytes::Bytes; /// Blockchain test header deserializer. #[derive(Debug, PartialEq, Deserialize)] pub struct Header { - bloom: Bloom, - coinbase: Address, - difficulty: Uint, + /// Blocks bloom. + pub bloom: Bloom, + /// Blocks author. + #[serde(rename="coinbase")] + pub author: Address, + /// Difficulty. + pub difficulty: Uint, #[serde(rename="extraData")] - extra_data: Bytes, + /// Extra data. + pub extra_data: Bytes, + /// Gas limit. #[serde(rename="gasLimit")] - gas_limit: Uint, + pub gas_limit: Uint, + /// Gas used. #[serde(rename="gasUsed")] - gas_used: Uint, - hash: H256, + pub gas_used: Uint, + /// Hash. + pub hash: H256, #[serde(rename="mixHash")] - mix_hash: H256, - nonce: H64, - number: Uint, + /// Mix hash. + pub mix_hash: H256, + /// Seal nonce. + pub nonce: H64, + /// Block number. + pub number: Uint, + /// Parent hash. #[serde(rename="parentHash")] - parent_hash: H256, + pub parent_hash: H256, + /// Receipt root. #[serde(rename="receiptTrie")] - receipt_trie: H256, + pub receipt_root: H256, + /// State root. #[serde(rename="stateRoot")] - state_root: H256, - timestamp: Uint, + pub state_root: H256, + /// Timestamp. + pub timestamp: Uint, + /// Transactions root. #[serde(rename="transactionsTrie")] - transactions_trie: H256, + pub transactions_root: H256, + /// Uncles hash. #[serde(rename="uncleHash")] - uncle_hash: H256, + pub uncles_hash: H256, } #[cfg(test)] diff --git a/json/src/hash.rs b/json/src/hash.rs index bece68011..c555b6266 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -25,7 +25,7 @@ use util::hash::{H64 as Hash64, Address as Hash160, H256 as Hash256, H2048 as Ha macro_rules! impl_hash { ($name: ident, $inner: ident) => { /// Lenient hash json deserialization for test json files. - #[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] + #[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] pub struct $name($inner); impl Into<$inner> for $name { diff --git a/json/src/spec/genesis.rs b/json/src/spec/genesis.rs index 4c66a9e35..a8b5b30e3 100644 --- a/json/src/spec/genesis.rs +++ b/json/src/spec/genesis.rs @@ -17,30 +17,39 @@ //! Spec genesis deserialization. use uint::Uint; -use hash::{Address, H256}; +use hash::{H64, Address, H256}; use bytes::Bytes; /// Spec genesis. #[derive(Debug, PartialEq, Deserialize)] pub struct Genesis { // old seal - nonce: Option, + /// Seal nonce. + pub nonce: Option, #[serde(rename="mixHash")] - mix_hash: Option, + /// Seal mix hash. + pub mix_hash: Option, // new seal // TODO: consider moving it to a separate seal structure #[serde(rename="sealFields")] - seal_fields: Option, + /// Number of seal fields. + pub seal_fields: Option, #[serde(rename="sealRlp")] - seal_rlp: Option, + /// Seal rlp. + pub seal_rlp: Option, - difficulty: Uint, - author: Address, - timestamp: Uint, + /// Difficulty. + pub difficulty: Uint, + /// Block author. + pub author: Address, + /// Block timestamp. + pub timestamp: Uint, + /// Parent hash. #[serde(rename="parentHash")] - parent_hash: H256, + pub parent_hash: H256, + /// Gas limit. #[serde(rename="gasLimit")] - gas_limit: Uint, + pub gas_limit: Uint, } #[cfg(test)] diff --git a/json/src/uint.rs b/json/src/uint.rs index 41e717277..2d24c3f7e 100644 --- a/json/src/uint.rs +++ b/json/src/uint.rs @@ -22,7 +22,7 @@ use serde::de::Visitor; use util::numbers::{U256, Uint as U}; /// Lenient uint json deserialization for test json files. -#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub struct Uint(U256); impl Into for Uint { From a285fbab6d7f807626b44a49271159cfc1d29872 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 17 Mar 2016 14:11:32 +0100 Subject: [PATCH 665/753] overhaul to flag --- ethcore/src/client/client.rs | 7 +----- ethcore/src/service.rs | 4 ++-- rpc/src/v1/impls/eth.rs | 2 +- sync/src/chain.rs | 41 ++++++++++++------------------------ sync/src/lib.rs | 7 ++---- sync/src/tests/helpers.rs | 2 +- 6 files changed, 21 insertions(+), 42 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d8c48e696..6ee1b88d5 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -324,6 +324,7 @@ impl Client where V: Verifier { invalid: invalid_blocks, enacted: enacted, retracted: retracted, + is_last: self.queue_info().is_empty() })).unwrap(); } } @@ -334,12 +335,6 @@ impl Client where V: Verifier { } } - { - if self.queue_info().is_empty() { - io.send(NetworkIoMessage::User(SyncMessage::BlockQueueEmpty)).expect("error sending message to sync module"); - } - } - imported } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 1c2385934..a46581e3c 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -35,13 +35,13 @@ pub enum SyncMessage { retracted: Vec, /// Hashes of blocks that are now included in cannonical chain enacted: Vec, + /// Set when blockqueue is empty + is_last: bool, }, /// Best Block Hash in chain has been changed NewChainHead, /// A block is ready BlockVerified, - /// blocks queue is empty - BlockQueueEmpty, } /// IO Message type used for Network service diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index b0e31ba97..520b37045 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -151,7 +151,7 @@ impl Eth for EthClient Params::None => { let status = take_weak!(self.sync).status(); let res = match status.state { - SyncState::NotSynced | SyncState::Idle | SyncState::FullySynced => SyncStatus::None, + SyncState::NotSynced | SyncState::Idle => SyncStatus::None, SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks => SyncStatus::Info(SyncInfo { starting_block: U256::from(status.start_block_number), current_block: U256::from(take_weak!(self.client).chain_info().best_block_number), diff --git a/sync/src/chain.rs b/sync/src/chain.rs index f7a03a7bd..def9ad7f4 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -116,8 +116,6 @@ pub enum SyncState { Blocks, /// Downloading blocks learned from NewHashes packet NewBlocks, - /// Once has an event that client finished processing new blocks - FullySynced, } /// Syncing status and statistics @@ -217,6 +215,8 @@ pub struct ChainSync { network_id: U256, /// Miner miner: Arc, + /// Fully-synced flag + is_fully_synced: bool, } type RlpResponseResult = Result, PacketDecodeError>; @@ -243,6 +243,7 @@ impl ChainSync { max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, miner: miner, + is_fully_synced: true, } } @@ -629,7 +630,7 @@ impl ChainSync { fn can_sync(&self) -> bool { match self.state { - SyncState::Idle | SyncState::NotSynced | SyncState::FullySynced => true, + SyncState::Idle | SyncState::NotSynced => true, _ => false } } @@ -947,7 +948,7 @@ impl ChainSync { /// Called when peer sends us new transactions fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { // accepting transactions once only fully synced - if self.state != SyncState::FullySynced { + if !self.is_fully_synced { return Ok(()); } @@ -1292,8 +1293,10 @@ impl ChainSync { } /// called when block is imported to chain, updates transactions queue and propagates the blocks - pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { - if self.state == SyncState::FullySynced { + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256], is_last: bool) { + // Set the state in which it can accept transactions from the net + self.is_fully_synced = is_last; + if self.is_fully_synced { // Notify miner self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); } @@ -1303,21 +1306,7 @@ impl ChainSync { } pub fn chain_new_head(&mut self, io: &mut SyncIo) { - if self.state == SyncState::FullySynced { - self.miner.prepare_sealing(io.chain()); - } - } - - // called once has nothing to download and client reports that all that downloaded is imported - pub fn set_fully_synced(&mut self) { - self.state = SyncState::FullySynced; - } - - // handles event from client about empty blow_queue - pub fn client_block_queue_empty(&mut self) { - if self.state == SyncState::Idle { - self.set_fully_synced(); - } + self.miner.prepare_sealing(io.chain()); } } @@ -1654,7 +1643,6 @@ mod tests { client.add_blocks(1, EachBlockWith::UncleAndTransaction); client.add_blocks(1, EachBlockWith::Transaction); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - sync.state = SyncState::FullySynced; let good_blocks = vec![client.block_hash_delta_minus(2)]; let retracted_blocks = vec![client.block_hash_delta_minus(1)]; @@ -1663,10 +1651,10 @@ mod tests { let mut io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, true); assert_eq!(sync.miner.status().transaction_queue_future, 0); assert_eq!(sync.miner.status().transaction_queue_pending, 1); - sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); + sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks, true); // then let status = sync.miner.status(); @@ -1682,7 +1670,6 @@ mod tests { client.add_blocks(1, EachBlockWith::UncleAndTransaction); client.add_blocks(1, EachBlockWith::Transaction); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - sync.state = SyncState::Idle; let good_blocks = vec![client.block_hash_delta_minus(2)]; let retracted_blocks = vec![client.block_hash_delta_minus(1)]; @@ -1691,10 +1678,10 @@ mod tests { let mut io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, false); assert_eq!(sync.miner.status().transaction_queue_future, 0); assert_eq!(sync.miner.status().transaction_queue_pending, 0); - sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); + sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks, false); // then let status = sync.miner.status(); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index d78ac3b89..8ab6a23e9 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -166,17 +166,14 @@ impl NetworkProtocolHandler for EthSync { fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { - SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => { + SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted, is_last } => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted); + self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted, is_last); }, SyncMessage::NewChainHead => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); self.sync.write().unwrap().chain_new_head(&mut sync_io); }, - SyncMessage::BlockQueueEmpty => { - self.sync.write().unwrap().client_block_queue_empty(); - } _ => {/* Ignore other messages */}, } } diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index b3e62ccc6..42ef728b9 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -168,6 +168,6 @@ impl TestNet { pub fn trigger_chain_new_blocks(&mut self, peer_id: usize) { let mut peer = self.peer_mut(peer_id); - peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[], &[]); + peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[], &[], true); } } From c4021a77ca2afee506b1fcb1ff4ab796c33f6a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 14:39:24 +0100 Subject: [PATCH 666/753] Stop adding transactions right after we know that no other will make it to block. --- ethcore/src/client/client.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 7818fcdc8..2c011047d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -418,26 +418,33 @@ impl BlockChainClient for Client where V: Verifier { // Add transactions let block_number = b.block().header().number(); + let min_tx_gas = U256::from(self.engine.schedule(&b.env_info()).tx_gas); let gas_limit = *b.block().header().gas_limit(); let mut gas_left = gas_limit; let mut invalid_transactions = HashSet::new(); for tx in transactions { - let hash = tx.hash(); - let gas = tx.gas; - // TODO [todr] It seems that calculating gas_left here doesn't really look nice. After moving this function + // Stop early if we are sure that no other transaction will be included + if gas_left < min_tx_gas { + break; + } + + // TODO [todr] It seems that calculating gas_left here doesn't look nice. After moving this function // to miner crate we should consider rewriting this logic in some better way. - if gas > gas_left { - trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); + if tx.gas > gas_left { + trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", tx.hash()); continue; } + // Push transaction to block + let hash = tx.hash(); let import = b.push_transaction(tx, None); match import { Err(e) => { - trace!(target: "miner", "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", - block_number, hash, e); invalid_transactions.insert(hash); + trace!(target: "miner", + "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", + block_number, hash, e); }, Ok(receipt) => { gas_left = gas_limit - receipt.gas_used; From 0f96ce9bd250d8718bd7c97657172dbae5bef96e Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 17 Mar 2016 14:56:19 +0100 Subject: [PATCH 667/753] no flag also --- ethcore/src/client/client.rs | 1 - ethcore/src/service.rs | 2 -- sync/src/chain.rs | 19 +++++++------------ sync/src/io.rs | 4 ++++ sync/src/lib.rs | 4 ++-- sync/src/tests/helpers.rs | 2 +- 6 files changed, 14 insertions(+), 18 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 6ee1b88d5..caa92db97 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -324,7 +324,6 @@ impl Client where V: Verifier { invalid: invalid_blocks, enacted: enacted, retracted: retracted, - is_last: self.queue_info().is_empty() })).unwrap(); } } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index a46581e3c..bcfe7724f 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -35,8 +35,6 @@ pub enum SyncMessage { retracted: Vec, /// Hashes of blocks that are now included in cannonical chain enacted: Vec, - /// Set when blockqueue is empty - is_last: bool, }, /// Best Block Hash in chain has been changed NewChainHead, diff --git a/sync/src/chain.rs b/sync/src/chain.rs index c94e89445..b68b2b250 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -215,8 +215,6 @@ pub struct ChainSync { network_id: U256, /// Miner miner: Arc, - /// Fully-synced flag - is_fully_synced: bool, } type RlpResponseResult = Result, PacketDecodeError>; @@ -243,7 +241,6 @@ impl ChainSync { max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, miner: miner, - is_fully_synced: true, } } @@ -948,7 +945,7 @@ impl ChainSync { /// Called when peer sends us new transactions fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { // accepting transactions once only fully synced - if !self.is_fully_synced { + if !io.is_chain_queue_empty() { return Ok(()); } @@ -1296,10 +1293,8 @@ impl ChainSync { } /// called when block is imported to chain, updates transactions queue and propagates the blocks - pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256], is_last: bool) { - // Set the state in which it can accept transactions from the net - self.is_fully_synced = is_last; - if self.is_fully_synced { + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { + if io.is_chain_queue_empty() { // Notify miner self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); } @@ -1662,10 +1657,10 @@ mod tests { let mut io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, true); + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); assert_eq!(sync.miner.status().transactions_in_future_queue, 0); assert_eq!(sync.miner.status().transactions_in_pending_queue, 1); - sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks, true); + sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); // then @@ -1690,10 +1685,10 @@ mod tests { let mut io = TestIo::new(&mut client, &mut queue, None); // when - sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks, false); + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); assert_eq!(sync.miner.status().transactions_in_future_queue, 0); assert_eq!(sync.miner.status().transactions_in_pending_queue, 0); - sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks, false); + sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); // then let status = sync.miner.status(); diff --git a/sync/src/io.rs b/sync/src/io.rs index 00ee49be4..84697a021 100644 --- a/sync/src/io.rs +++ b/sync/src/io.rs @@ -37,6 +37,10 @@ pub trait SyncIo { fn peer_info(&self, peer_id: PeerId) -> String { peer_id.to_string() } + /// Returns if the chain block queue empty + fn is_chain_queue_empty(&self) -> bool { + self.chain().queue_info().is_empty() + } } /// Wraps `NetworkContext` and the blockchain client diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 8ab6a23e9..a4f6eff38 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -166,9 +166,9 @@ impl NetworkProtocolHandler for EthSync { fn message(&self, io: &NetworkContext, message: &SyncMessage) { match *message { - SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted, is_last } => { + SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted, is_last); + self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted); }, SyncMessage::NewChainHead => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 42ef728b9..b3e62ccc6 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -168,6 +168,6 @@ impl TestNet { pub fn trigger_chain_new_blocks(&mut self, peer_id: usize) { let mut peer = self.peer_mut(peer_id); - peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[], &[], true); + peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[], &[]); } } From 7929af67c8b875dd62d644f18c092b1dd44b421a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 17 Mar 2016 15:02:18 +0100 Subject: [PATCH 668/753] propagation is out --- sync/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index b68b2b250..e1f0032a1 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1297,9 +1297,9 @@ impl ChainSync { if io.is_chain_queue_empty() { // Notify miner self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); + // Propagate latests blocks + self.propagate_latest_blocks(io); } - // Propagate latests blocks - self.propagate_latest_blocks(io); // TODO [todr] propagate transactions? } From 85b08e6e7bd63ec3ef165d81484f027ebea697f4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 17 Mar 2016 15:09:08 +0100 Subject: [PATCH 669/753] get rid of the function --- sync/src/chain.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index e1f0032a1..57eb101cb 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -625,13 +625,6 @@ impl ChainSync { self.state = SyncState::Waiting; } - fn can_sync(&self) -> bool { - match self.state { - SyncState::Idle | SyncState::NotSynced => true, - _ => false - } - } - /// Find something to do for a peer. Called for a new peer or when a peer is done with it's task. fn sync_peer(&mut self, io: &mut SyncIo, peer_id: PeerId, force: bool) { let (peer_latest, peer_difficulty) = { @@ -651,7 +644,7 @@ impl ChainSync { if force || peer_difficulty > syncing_difficulty { // start sync self.syncing_difficulty = peer_difficulty; - if self.can_sync() { + if self.state == SyncState::Idle || self.state == SyncState::NotSynced { self.state = SyncState::Blocks; } trace!(target: "sync", "Starting sync with better chain"); @@ -1662,7 +1655,6 @@ mod tests { assert_eq!(sync.miner.status().transactions_in_pending_queue, 1); sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); - // then let status = sync.miner.status(); assert_eq!(status.transactions_in_pending_queue, 1); From 1f03ae54d69f1982ee6d2f6e82d599aaa9b16817 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 17 Mar 2016 15:15:10 +0100 Subject: [PATCH 670/753] moved ethcores spec to its own module, added genesis --- Cargo.lock | 1 + ethcore/Cargo.toml | 1 + ethcore/src/lib.rs | 1 + ethcore/src/spec/genesis.rs | 91 +++++++++++++++++++++++++++++++ ethcore/src/spec/mod.rs | 22 ++++++++ ethcore/src/{ => spec}/spec.rs | 32 ++++++++++- json/src/blockchain/blockchain.rs | 5 ++ json/src/blockchain/header.rs | 2 +- json/src/spec/genesis.rs | 17 +++++- json/src/uint.rs | 6 ++ 10 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 ethcore/src/spec/genesis.rs create mode 100644 ethcore/src/spec/mod.rs rename ethcore/src/{ => spec}/spec.rs (92%) diff --git a/Cargo.lock b/Cargo.lock index 1a701042e..daf0501ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,6 +216,7 @@ dependencies = [ "ethash 1.1.0", "ethcore-devtools 1.1.0", "ethcore-util 1.1.0", + "ethjson 0.1.0", "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 1d16cc34a..cf75949f1 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -21,6 +21,7 @@ clippy = { version = "0.0.50", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } +ethjson = { path = "../json" } [features] jit = ["evmjit"] diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 572cda2fa..662dea641 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -83,6 +83,7 @@ extern crate time; extern crate env_logger; extern crate num_cpus; extern crate crossbeam; +extern crate ethjson; #[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(feature = "jit" )] extern crate evmjit; diff --git a/ethcore/src/spec/genesis.rs b/ethcore/src/spec/genesis.rs new file mode 100644 index 000000000..686e8f6d1 --- /dev/null +++ b/ethcore/src/spec/genesis.rs @@ -0,0 +1,91 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::rlp::*; +use util::numbers::{Uint, U256}; +use util::hash::{H64, Address, H256}; +use ethjson; + +/// Genesis seal type. +pub enum Seal { + /// Classic ethereum seal. + Ethereum { + /// Seal nonce. + nonce: H64, + /// Seal mix hash. + mix_hash: H256, + }, + /// Generic seal. + Generic { + /// Number of seal fields. + fields: usize, + /// Seal rlp. + rlp: Vec, + }, +} + +/// Genesis components. +pub struct Genesis { + /// Seal. + pub seal: Seal, + /// Difficulty. + pub difficulty: U256, + /// Author. + pub author: Address, + /// Timestamp. + pub timestamp: u64, + /// Parent hash. + pub parent_hash: H256, + /// Gas limit. + pub gas_limit: U256, + /// Transactions root. + pub transactions_root: H256, + /// Receipts root. + pub receipts_root: H256, + /// State root. + pub state_root: Option, + /// Gas used. + pub gas_used: U256, + /// Extra data. + pub extra_data: Vec, +} + +impl From for Genesis { + fn from(g: ethjson::spec::Genesis) -> Self { + Genesis { + seal: match (g.nonce, g.mix_hash) { + (Some(nonce), Some(mix_hash)) => Seal::Ethereum { + nonce: nonce.into(), + mix_hash: mix_hash.into(), + }, + _ => Seal::Generic { + fields: g.seal_fields.unwrap(), + rlp: g.seal_rlp.unwrap().into(), + } + }, + difficulty: g.difficulty.into(), + author: g.author.into(), + timestamp: g.timestamp.into(), + parent_hash: g.parent_hash.into(), + gas_limit: g.gas_limit.into(), + transactions_root: g.transactions_root.map_or_else(|| SHA3_NULL_RLP.clone(), Into::into), + receipts_root: g.receipts_root.map_or_else(|| SHA3_NULL_RLP.clone(), Into::into), + state_root: g.state_root.map(Into::into), + gas_used: g.gas_used.map_or_else(U256::zero, Into::into), + extra_data: g.extra_data.map_or_else(Vec::new, Into::into), + } + } +} diff --git a/ethcore/src/spec/mod.rs b/ethcore/src/spec/mod.rs new file mode 100644 index 000000000..e9c7a0356 --- /dev/null +++ b/ethcore/src/spec/mod.rs @@ -0,0 +1,22 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Blockchain params. + +mod genesis; +pub mod spec; + +pub use self::spec::*; diff --git a/ethcore/src/spec.rs b/ethcore/src/spec/spec.rs similarity index 92% rename from ethcore/src/spec.rs rename to ethcore/src/spec/spec.rs index 2208350cc..c7e2e4e9f 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -21,6 +21,8 @@ use engine::*; use pod_state::*; use null_engine::*; use account_db::*; +use ethereum; +use super::genesis::{Seal as GenesisSeal, Genesis}; /// Convert JSON value to equivalent RLP representation. // TODO: handle container types. @@ -106,7 +108,7 @@ impl Spec { pub fn to_engine(self) -> Result, Error> { match self.engine_name.as_ref() { "NullEngine" => Ok(NullEngine::new_boxed(self)), - "Ethash" => Ok(super::ethereum::Ethash::new_boxed(self)), + "Ethash" => Ok(ethereum::Ethash::new_boxed(self)), _ => Err(Error::UnknownEngineName(self.engine_name.clone())) } } @@ -197,6 +199,32 @@ impl Spec { self.state_root_memo = RwLock::new(genesis.find("stateRoot").and_then(|_| Some(H256::from_json(&genesis["stateRoot"])))); } + /// Overwrite the genesis components. + pub fn overwrite_genesis_params(&mut self, g: Genesis) { + let (seal_fields, seal_rlp) = match g.seal { + GenesisSeal::Generic { fields, rlp } => (fields, rlp), + GenesisSeal::Ethereum { nonce, mix_hash } => { + let mut s = RlpStream::new(); + s.append(&mix_hash); + s.append(&nonce); + (2, s.out()) + } + }; + + self.parent_hash = g.parent_hash; + self.transactions_root = g.transactions_root; + self.receipts_root = g.receipts_root; + self.author = g.author; + self.difficulty = g.difficulty; + self.gas_limit = g.gas_limit; + self.gas_used = g.gas_used; + self.timestamp = g.timestamp; + self.extra_data = g.extra_data; + self.seal_fields = seal_fields; + self.seal_rlp = seal_rlp; + self.state_root_memo = RwLock::new(g.state_root); + } + /// Alter the value of the genesis state. pub fn set_genesis_state(&mut self, s: PodState) { self.genesis_state = s; @@ -304,7 +332,7 @@ impl Spec { } /// Create a new Spec which conforms to the Morden chain except that it's a NullEngine consensus. - pub fn new_test() -> Spec { Self::from_json_utf8(include_bytes!("../res/null_morden.json")) } + pub fn new_test() -> Spec { Self::from_json_utf8(include_bytes!("../../res/null_morden.json")) } } #[cfg(test)] diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 75d321a4d..d9e879ae9 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -59,6 +59,11 @@ impl BlockChain { timestamp: self.genesis_block.timestamp, parent_hash: self.genesis_block.parent_hash.clone(), gas_limit: self.genesis_block.gas_limit, + transactions_root: Some(self.genesis_block.transactions_root.clone()), + receipts_root: Some(self.genesis_block.receipts_root.clone()), + state_root: Some(self.genesis_block.state_root.clone()), + gas_used: Some(self.genesis_block.gas_used), + extra_data: Some(self.genesis_block.extra_data.clone()), } } } diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index f4ebee01b..ece6d6359 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -53,7 +53,7 @@ pub struct Header { pub parent_hash: H256, /// Receipt root. #[serde(rename="receiptTrie")] - pub receipt_root: H256, + pub receipts_root: H256, /// State root. #[serde(rename="stateRoot")] pub state_root: H256, diff --git a/json/src/spec/genesis.rs b/json/src/spec/genesis.rs index a8b5b30e3..a2b484397 100644 --- a/json/src/spec/genesis.rs +++ b/json/src/spec/genesis.rs @@ -33,7 +33,7 @@ pub struct Genesis { // new seal // TODO: consider moving it to a separate seal structure #[serde(rename="sealFields")] /// Number of seal fields. - pub seal_fields: Option, + pub seal_fields: Option, #[serde(rename="sealRlp")] /// Seal rlp. pub seal_rlp: Option, @@ -50,6 +50,21 @@ pub struct Genesis { /// Gas limit. #[serde(rename="gasLimit")] pub gas_limit: Uint, + /// Transactions root. + #[serde(rename="transactionsRoot")] + pub transactions_root: Option, + /// Receipts root. + #[serde(rename="receiptsRoot")] + pub receipts_root: Option, + /// State root. + #[serde(rename="stateRoot")] + pub state_root: Option, + /// Gas used. + #[serde(rename="gasUsed")] + pub gas_used: Option, + /// Extra data. + #[serde(rename="extraData")] + pub extra_data: Option, } #[cfg(test)] diff --git a/json/src/uint.rs b/json/src/uint.rs index 2d24c3f7e..f6eae80e4 100644 --- a/json/src/uint.rs +++ b/json/src/uint.rs @@ -31,6 +31,12 @@ impl Into for Uint { } } +impl Into for Uint { + fn into(self) -> u64 { + u64::from(self.0) + } +} + impl Deserialize for Uint { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { From 309af743e08d1f066781c0bbc86d5467eac607cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 15:20:33 +0100 Subject: [PATCH 671/753] Ignoring transactions slightly above gas_limit --- ethcore/src/error.rs | 7 ++++ miner/src/miner.rs | 17 +++++++-- miner/src/transaction_queue.rs | 65 ++++++++++++++++++++++++++++++++-- 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 482a8de01..a3a379463 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -79,6 +79,13 @@ pub enum TransactionError { /// Transaction cost cost: U256, }, + /// Transactions gas is higher then current gas limit + GasLimitExceeded { + /// Current gas limit + limit: U256, + /// Declared transaction gas + got: U256, + }, /// Transaction's gas limit (aka gas) is invalid. InvalidGasLimit(OutOfBounds), } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 832dc5d02..22319b313 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -21,7 +21,7 @@ use std::sync::atomic::AtomicBool; use std::collections::HashSet; use util::{H256, U256, Address, Bytes, Uint}; -use ethcore::views::{BlockView}; +use ethcore::views::{BlockView, HeaderView}; use ethcore::client::{BlockChainClient, BlockId}; use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::error::{Error}; @@ -94,6 +94,12 @@ impl Miner { pub fn set_minimal_gas_price(&self, min_gas_price: U256) { self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price); } + + fn update_gas_limit(&self, chain: &BlockChainClient) { + let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit(); + let mut queue = self.transaction_queue.lock().unwrap(); + queue.set_gas_limit(gas_limit); + } } impl MinerService for Miner { @@ -177,6 +183,11 @@ impl MinerService for Miner { let block = BlockView::new(&block); block.transactions() } + + // First update gas limit in transaction queue + self.update_gas_limit(chain); + + // Then import all transactions... { let out_of_chain = retracted .par_iter() @@ -193,7 +204,8 @@ impl MinerService for Miner { }); }); } - // First import all transactions and after that remove old ones + + // ...and after that remove old ones { let in_chain = { let mut in_chain = HashSet::new(); @@ -219,6 +231,7 @@ impl MinerService for Miner { }); } + // Update mined block if self.sealing_enabled.load(atomic::Ordering::Relaxed) { self.prepare_sealing(chain); } diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index a1fc20b0f..a530cbf72 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -252,10 +252,16 @@ pub struct AccountDetails { pub balance: U256, } + +/// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue. +const GAS_LIMIT_HYSTERESIS: usize = 10; // % + /// TransactionQueue implementation pub struct TransactionQueue { /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) minimal_gas_price: U256, + /// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0) + gas_limit: U256, /// Priority queue for transactions that can go to block current: TransactionSet, /// Priority queue for transactions that has been received but are not yet valid to go to block @@ -293,6 +299,7 @@ impl TransactionQueue { TransactionQueue { minimal_gas_price: U256::zero(), + gas_limit: !U256::zero(), current: current, future: future, by_hash: HashMap::new(), @@ -301,11 +308,22 @@ impl TransactionQueue { } /// Sets new gas price threshold for incoming transactions. - /// Any transactions already imported to the queue are not affected. + /// Any transaction already imported to the queue is not affected. pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) { self.minimal_gas_price = min_gas_price; } + /// Sets new gas limit. Transactions with gas slightly (`GAS_LIMIT_HYSTERESIS`) above the limit won't be imported. + /// Any transaction already imported to the queue is not affected. + pub fn set_gas_limit(&mut self, gas_limit: U256) { + let extra = gas_limit / U256::from(GAS_LIMIT_HYSTERESIS); + + self.gas_limit = match gas_limit.overflowing_add(extra) { + (_, true) => !U256::zero(), + (val, false) => val, + }; + } + // Will be used when rpc merged #[allow(dead_code)] /// Returns current status for this queue @@ -337,12 +355,24 @@ impl TransactionQueue { tx.hash(), tx.gas_price, self.minimal_gas_price ); - return Err(Error::Transaction(TransactionError::InsufficientGasPrice{ + return Err(Error::Transaction(TransactionError::InsufficientGasPrice { minimal: self.minimal_gas_price, got: tx.gas_price, })); } + if tx.gas > self.gas_limit { + trace!(target: "miner", + "Dropping transaction above gas limit: {:?} ({} > {})", + tx.hash(), tx.gas, self.gas_limit + ); + + return Err(Error::Transaction(TransactionError::GasLimitExceeded { + limit: self.gas_limit, + got: tx.gas, + })); + } + let vtx = try!(VerifiedTransaction::new(tx)); let account = fetch_account(&vtx.sender()); @@ -682,6 +712,37 @@ mod test { assert_eq!(stats.pending, 1); } + #[test] + fn gas_limit_should_never_overflow() { + // given + let mut txq = TransactionQueue::new(); + txq.set_gas_limit(U256::zero()); + assert_eq!(txq.gas_limit, U256::zero()); + + // when + txq.set_gas_limit(!U256::zero()); + + // then + assert_eq!(txq.gas_limit, !U256::zero()); + } + + #[test] + fn should_not_import_transaction_above_gas_limit() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + txq.set_gas_limit(tx.gas / U256::from(2)); + + // when + txq.add(tx, &default_nonce).unwrap_err(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + + #[test] fn should_drop_transactions_from_senders_without_balance() { // given From fece330ca4e2cc31a9a22ea7705033b9e967fb4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 15:30:03 +0100 Subject: [PATCH 672/753] Refactoring removing invalid transactions from queue --- miner/src/miner.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 776cf7c83..6be2da512 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -133,19 +133,14 @@ impl MinerService for Miner { transactions, ); - match b { - None => { - *self.sealing_block.lock().unwrap() = None - }, - Some((block, invalid_transactions)) => { - let mut queue = self.transaction_queue.lock().unwrap(); - queue.remove_all( - &invalid_transactions.into_iter().collect::>(), - |a: &Address| chain.nonce(a) - ); - *self.sealing_block.lock().unwrap() = Some(block) - } - } + *self.sealing_block.lock().unwrap() = b.map(|(block, invalid_transactions)| { + let mut queue = self.transaction_queue.lock().unwrap(); + queue.remove_all( + &invalid_transactions.into_iter().collect::>(), + |a: &Address| chain.nonce(a) + ); + block + }); } fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { From c695b83e52329a4f0cca8a53e482ab4bb295b307 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 17 Mar 2016 15:51:40 +0100 Subject: [PATCH 673/753] new way of loading PodState --- ethcore/src/lib.rs | 2 +- ethcore/src/pod_account.rs | 16 ++++++++++++++++ ethcore/src/pod_state.rs | 14 +++++++++++++- ethcore/src/spec/mod.rs | 1 + json/src/blockchain/account.rs | 17 +++++++++++------ json/src/blockchain/blockchain.rs | 15 ++++++++++----- json/src/blockchain/state.rs | 4 ++-- parity/rpctest.rs | 12 ++++++++++++ 8 files changed, 66 insertions(+), 15 deletions(-) diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 662dea641..dfa321639 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -101,13 +101,13 @@ pub mod spec; pub mod transaction; pub mod views; pub mod receipt; +pub mod pod_state; mod common; mod basic_types; #[macro_use] mod evm; mod env_info; mod pod_account; -mod pod_state; mod account_diff; mod state_diff; mod engine; diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index d2690051c..8f38326ca 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -17,6 +17,7 @@ use util::*; use account::*; use account_db::*; +use ethjson; #[derive(Debug,Clone,PartialEq,Eq)] /// An account, expressed as Plain-Old-Data (hence the name). @@ -73,6 +74,21 @@ impl PodAccount { } } +impl From for PodAccount { + fn from(a: ethjson::blockchain::Account) -> Self { + PodAccount { + balance: a.balance.into(), + nonce: a.nonce.into(), + code: a.code.into(), + storage: a.storage.into_iter().fold(BTreeMap::new(), |mut acc, (key, value)| { + let key: U256 = key.into(); + acc.insert(H256::from(key), value.into()); + acc + }) + } + } +} + impl fmt::Display for PodAccount { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.len(), self.code.sha3(), self.storage.len()) diff --git a/ethcore/src/pod_state.rs b/ethcore/src/pod_state.rs index b873249ac..5782803ef 100644 --- a/ethcore/src/pod_state.rs +++ b/ethcore/src/pod_state.rs @@ -14,11 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! State of all accounts in the system expressed in Plain Old Data. + use util::*; use pod_account::*; +use ethjson; -#[derive(Debug,Clone,PartialEq,Eq,Default)] /// State of all accounts in the system expressed in Plain Old Data. +#[derive(Debug,Clone,PartialEq,Eq,Default)] pub struct PodState (BTreeMap); impl PodState { @@ -64,6 +67,15 @@ impl FromJson for PodState { } } +impl From for PodState { + fn from(s: ethjson::blockchain::State) -> PodState { + PodState(s.0.into_iter().fold(BTreeMap::new(), |mut acc, (key, value)| { + acc.insert(key.into(), PodAccount::from(value)); + acc + })) + } +} + impl fmt::Display for PodState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (add, acc) in &self.0 { diff --git a/ethcore/src/spec/mod.rs b/ethcore/src/spec/mod.rs index e9c7a0356..b85165d89 100644 --- a/ethcore/src/spec/mod.rs +++ b/ethcore/src/spec/mod.rs @@ -20,3 +20,4 @@ mod genesis; pub mod spec; pub use self::spec::*; +pub use self::genesis::Genesis; diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs index eb6f0a1dd..990c024c7 100644 --- a/json/src/blockchain/account.rs +++ b/json/src/blockchain/account.rs @@ -19,14 +19,19 @@ use std::collections::BTreeMap; use uint::Uint; use bytes::Bytes; +use hash::H256; /// Blockchain test account deserializer. -#[derive(Debug, PartialEq, Deserialize)] +#[derive(Debug, PartialEq, Deserialize, Clone)] pub struct Account { - balance: Uint, - code: Bytes, - nonce: Uint, - storage: BTreeMap, + /// Balance. + pub balance: Uint, + /// Code. + pub code: Bytes, + /// Nonce. + pub nonce: Uint, + /// Storage. + pub storage: BTreeMap, } #[cfg(test)] @@ -35,7 +40,7 @@ mod tests { use blockchain::account::Account; #[test] - fn header_deserialization() { + fn account_deserialization() { let s = r#"{ "balance" : "0x09184e72a078", "code" : "0x600140600155", diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index d9e879ae9..4783819e5 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -25,15 +25,20 @@ use spec::Genesis; /// Blockchain deserialization. #[derive(Debug, PartialEq, Deserialize)] pub struct BlockChain { + /// Genesis block header. #[serde(rename="genesisBlockHeader")] - genesis_block: Header, + pub genesis_block: Header, + /// Genesis block rlp. #[serde(rename="genesisRLP")] - genesis_rlp: Bytes, - blocks: Vec, + pub genesis_rlp: Bytes, + /// Blocks. + pub blocks: Vec, + /// Post state. #[serde(rename="postState")] - post_state: State, + pub post_state: State, + /// Pre state. #[serde(rename="pre")] - pre_state: State, + pub pre_state: State, } impl BlockChain { diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs index 2af0dbf21..51e77e95e 100644 --- a/json/src/blockchain/state.rs +++ b/json/src/blockchain/state.rs @@ -22,8 +22,8 @@ use hash::Address; use blockchain::account::Account; /// Blockchain test state deserializer. -#[derive(Debug, PartialEq, Deserialize)] -pub struct State(BTreeMap); +#[derive(Debug, PartialEq, Deserialize, Clone)] +pub struct State(pub BTreeMap); impl Deref for State { type Target = BTreeMap; diff --git a/parity/rpctest.rs b/parity/rpctest.rs index 182f6dfed..ca12eed93 100644 --- a/parity/rpctest.rs +++ b/parity/rpctest.rs @@ -18,11 +18,15 @@ extern crate docopt; extern crate rustc_serialize; extern crate serde_json; extern crate ethjson; +extern crate ethcore; use std::process; use std::fs::File; use std::path::Path; use docopt::Docopt; +use ethcore::spec::Genesis; +use ethcore::pod_state::PodState; +use ethcore::ethereum; const USAGE: &'static str = r#" Parity rpctest client. @@ -70,7 +74,15 @@ impl Configuration { process::exit(3); }); + let genesis = Genesis::from(blockchain.genesis()); + let state = PodState::from(blockchain.pre_state.clone()); + let mut spec = ethereum::new_frontier_test(); + spec.set_genesis_state(state); + spec.overwrite_genesis_params(genesis); + assert!(spec.is_state_root_valid()); + //let temp = RandomTempPath::new(); + //spec. } } From 7ae60056b21e9ca42c3b977af995f6f365a2072b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 15:49:29 +0100 Subject: [PATCH 674/753] Common error handling --- ethcore/src/error.rs | 4 ++++ miner/src/lib.rs | 2 +- miner/src/miner.rs | 2 +- miner/src/transaction_queue.rs | 28 +++++++++++++++------------- rpc/src/v1/impls/eth.rs | 2 +- sync/src/chain.rs | 3 ++- 6 files changed, 24 insertions(+), 17 deletions(-) diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 482a8de01..1b01ec9c9 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -65,6 +65,10 @@ pub enum ExecutionError { #[derive(Debug)] /// Errors concerning transaction processing. pub enum TransactionError { + /// Transaction is already imported to the queue + AlreadyImported, + /// Transaction is not valid anymore (state already has higher nonce) + Old, /// Transaction's gas price is below threshold. InsufficientGasPrice { /// Minimal expected gas price diff --git a/miner/src/lib.rs b/miner/src/lib.rs index c70caad66..b79a13e24 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -79,7 +79,7 @@ pub trait MinerService : Send + Sync { fn status(&self) -> MinerStatus; /// Imports transactions to transaction queue. - fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Result<(), Error> + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails; /// Returns hashes of transactions currently in pending diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 9d3613085..865bad10c 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -128,7 +128,7 @@ impl MinerService for Miner { } } - fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Result<(), Error> + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails { let mut transaction_queue = self.transaction_queue.lock().unwrap(); transaction_queue.add_all(transactions, fetch_account) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index a1fc20b0f..b34cee6f5 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -317,12 +317,12 @@ impl TransactionQueue { } /// Adds all signed transactions to queue to be verified and imported - pub fn add_all(&mut self, txs: Vec, fetch_account: T) -> Result<(), Error> + pub fn add_all(&mut self, txs: Vec, fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails { - for tx in txs.into_iter() { - try!(self.add(tx, &fetch_account)); - } - Ok(()) + + txs.into_iter() + .map(|tx| self.add(tx, &fetch_account)) + .collect() } /// Add signed transaction to queue to be verified and imported @@ -357,8 +357,7 @@ impl TransactionQueue { })); } - self.import_tx(vtx, account.nonce); - Ok(()) + self.import_tx(vtx, account.nonce).map_err(Error::Transaction) } /// Removes all transactions identified by hashes given in slice @@ -515,12 +514,14 @@ impl TransactionQueue { /// /// It ignores transactions that has already been imported (same `hash`) and replaces the transaction /// iff `(address, nonce)` is the same but `gas_price` is higher. - fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) { + /// + /// Returns `true` when transaction was imported successfuly + fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) -> Result<(), TransactionError> { if self.by_hash.get(&tx.hash()).is_some() { // Transaction is already imported. trace!(target: "miner", "Dropping already imported transaction: {:?}", tx.hash()); - return; + return Err(TransactionError::AlreadyImported); } @@ -537,11 +538,11 @@ impl TransactionQueue { // We have a gap - put to future Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash); self.future.enforce_limit(&mut self.by_hash); - return; + return Ok(()); } else if nonce < state_nonce { // Droping transaction trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce); - return; + return Err(TransactionError::Old); } Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash); @@ -551,6 +552,7 @@ impl TransactionQueue { self.current.enforce_limit(&mut self.by_hash); trace!(target: "miner", "status: {:?}", self.status()); + Ok(()) } /// Replaces transaction in given set (could be `future` or `current`). @@ -952,7 +954,7 @@ mod test { let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() }; // when - txq.add(tx, &fetch_last_nonce).unwrap(); + txq.add(tx, &fetch_last_nonce).unwrap_err(); // then let stats = txq.status(); @@ -972,7 +974,7 @@ mod test { assert_eq!(txq.status().pending, 0); // when - txq.add(tx2.clone(), &nonce).unwrap(); + txq.add(tx2.clone(), &nonce).unwrap_err(); // then let stats = txq.status(); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 7ecfb86de..5cd1b2966 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -385,7 +385,7 @@ impl Eth for EthClient nonce: client.nonce(a), balance: client.balance(a), }); - match import { + match import.into_iter().collect::, _>>() { Ok(_) => to_value(&hash), Err(e) => { warn!("Error sending transaction: {:?}", e); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 8e8d4623c..044de613c 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -951,7 +951,8 @@ impl ChainSync { balance: chain.balance(a), }; let res = self.miner.import_transactions(transactions, fetch_account); - if res.is_ok() { + let any_transaction_imported = res.into_iter().any(|r| r.is_ok()); + if any_transaction_imported { self.miner.update_sealing(io.chain()); } Ok(()) From 2dc314f99373d68beb4fb0f7f10003de28aca48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 17 Mar 2016 17:19:46 +0100 Subject: [PATCH 675/753] Removing update_seal when new transactions arrives --- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- sync/src/chain.rs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index ca4151ba7..ad9dcaedd 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -48,7 +48,7 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_transactions(&self, _transactions: Vec, _fetch_account: T) -> Result<(), Error> + fn import_transactions(&self, _transactions: Vec, _fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails { unimplemented!(); } /// Returns hashes of transactions currently in pending diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 044de613c..1d87e5e20 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -950,11 +950,7 @@ impl ChainSync { nonce: chain.nonce(a), balance: chain.balance(a), }; - let res = self.miner.import_transactions(transactions, fetch_account); - let any_transaction_imported = res.into_iter().any(|r| r.is_ok()); - if any_transaction_imported { - self.miner.update_sealing(io.chain()); - } + let _ = self.miner.import_transactions(transactions, fetch_account); Ok(()) } From b1793fcb166ff8f8e49329a37fc621276b4795b3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 17 Mar 2016 18:41:55 +0100 Subject: [PATCH 676/753] Prettier version wo git dir; Use rustc compile time version --- util/Cargo.toml | 2 +- util/build.rs | 14 ++++++++++++++ util/src/lib.rs | 2 -- util/src/misc.rs | 12 +++++++++--- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/util/Cargo.toml b/util/Cargo.toml index 641036191..ae99ef20b 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -29,7 +29,6 @@ sha3 = { path = "sha3" } serde = "0.7.0" clippy = { version = "0.0.50", optional = true } json-tests = { path = "json-tests" } -rustc_version = "0.1.0" igd = "0.4.2" ethcore-devtools = { path = "../devtools" } libc = "0.2.7" @@ -44,3 +43,4 @@ dev = ["clippy"] [build-dependencies] vergen = "*" +rustc_version = "0.1.0" diff --git a/util/build.rs b/util/build.rs index b0b64a380..f033e52e0 100644 --- a/util/build.rs +++ b/util/build.rs @@ -15,9 +15,23 @@ // along with Parity. If not, see . extern crate vergen; +extern crate rustc_version; use vergen::*; +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::Path; fn main() { vergen(OutputFns::all()).unwrap(); + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("rustc_version.rs"); + let mut f = File::create(&dest_path).unwrap(); + f.write_all(format!(" + /// Returns compiler version. + pub fn rustc_version() -> &'static str {{ + \"{}\" + }} + ", rustc_version::version()).as_bytes()).unwrap(); } diff --git a/util/src/lib.rs b/util/src/lib.rs index cdc3a3f19..6abf6485d 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -109,9 +109,7 @@ extern crate log as rlog; extern crate igd; extern crate ethcore_devtools as devtools; extern crate libc; -extern crate rustc_version; extern crate target_info; -extern crate vergen; extern crate bigint; extern crate chrono; diff --git a/util/src/misc.rs b/util/src/misc.rs index 8dcd25988..76accf93b 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -20,9 +20,9 @@ use std::fs::File; use common::*; use rlp::{Stream, RlpStream}; use target_info::Target; -use rustc_version; include!(concat!(env!("OUT_DIR"), "/version.rs")); +include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); #[derive(Debug,Clone,PartialEq,Eq)] /// Diff type for specifying a change (or not). @@ -70,7 +70,13 @@ pub fn contents(name: &str) -> Result { /// Get the standard version string for this software. pub fn version() -> String { - format!("Parity/v{}-unstable-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) + let sha3 = short_sha(); + let sha3_dash = if sha3.is_empty() { "" } else { "-" }; + let commit_date = commit_date().replace("-", ""); + let date_dash = if commit_date.is_empty() { "" } else { "-" }; + let env = Target::env(); + let env_dash = if env.is_empty() { "" } else { "-" }; + format!("Parity/v{}-unstable{}{}{}{}/{}-{}{}{}/rustc{}", env!("CARGO_PKG_VERSION"), sha3_dash, sha3, date_dash, commit_date, Target::arch(), Target::os(), env_dash, env, rustc_version()) } /// Get the standard version data for this software. @@ -82,7 +88,7 @@ pub fn version_data() -> Bytes { u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(); s.append(&v); s.append(&"Parity"); - s.append(&format!("{}", rustc_version::version())); + s.append(&format!("{}", rustc_version())); s.append(&&Target::os()[0..2]); s.out() } From a61d1d8d51c9fd3c17c792f3bf4c268e7c8c44a6 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 17 Mar 2016 18:43:01 +0100 Subject: [PATCH 677/753] Indent --- util/build.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util/build.rs b/util/build.rs index f033e52e0..1ec89f704 100644 --- a/util/build.rs +++ b/util/build.rs @@ -26,12 +26,12 @@ use std::path::Path; fn main() { vergen(OutputFns::all()).unwrap(); let out_dir = env::var("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir).join("rustc_version.rs"); - let mut f = File::create(&dest_path).unwrap(); + let dest_path = Path::new(&out_dir).join("rustc_version.rs"); + let mut f = File::create(&dest_path).unwrap(); f.write_all(format!(" /// Returns compiler version. - pub fn rustc_version() -> &'static str {{ + pub fn rustc_version() -> &'static str {{ \"{}\" - }} - ", rustc_version::version()).as_bytes()).unwrap(); + }} + ", rustc_version::version()).as_bytes()).unwrap(); } From 3e6d0602ea86fb664f2704a97aea5f452ed6bfbf Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 17 Mar 2016 23:58:30 +0100 Subject: [PATCH 678/753] running rpc tests --- parity/rpctest.rs | 57 ++++++++++++++++++++++++++++++++++++++--- rpc/src/v1/mod.rs | 3 +-- rpc/src/v1/tests/mod.rs | 6 ++++- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/parity/rpctest.rs b/parity/rpctest.rs index ca12eed93..d972a779e 100644 --- a/parity/rpctest.rs +++ b/parity/rpctest.rs @@ -14,19 +14,32 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +extern crate ctrlc; extern crate docopt; extern crate rustc_serialize; extern crate serde_json; extern crate ethjson; +extern crate ethcore_util as util; extern crate ethcore; +extern crate ethcore_devtools as devtools; +extern crate ethcore_rpc as rpc; +use std::collections::HashMap; +use std::sync::{Arc, Mutex, Condvar}; use std::process; use std::fs::File; use std::path::Path; use docopt::Docopt; +use ctrlc::CtrlC; use ethcore::spec::Genesis; use ethcore::pod_state::PodState; use ethcore::ethereum; +use ethcore::client::{BlockChainClient, Client, ClientConfig}; +use devtools::RandomTempPath; +use util::io::IoChannel; +use rpc::v1::tests::helpers::{TestSyncProvider, Config as SyncConfig, TestMinerService, TestAccountProvider}; +use rpc::v1::{Eth, EthClient}; +use util::panics::MayPanic; const USAGE: &'static str = r#" Parity rpctest client. @@ -34,13 +47,22 @@ Parity rpctest client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity --json --name + parity --json --name [options] + parity --help + +Options: + --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API + server [default: 127.0.0.1]. + --jsonrpc-port PORT Specify the port portion of the JSONRPC API server + [default: 8545]. "#; #[derive(Debug, RustcDecodable)] struct Args { arg_test_file: String, arg_test_name: String, + flag_jsonrpc_addr: String, + flag_jsonrpc_port: u16, } struct Configuration { @@ -81,8 +103,37 @@ impl Configuration { spec.overwrite_genesis_params(genesis); assert!(spec.is_state_root_valid()); - //let temp = RandomTempPath::new(); - //spec. + let temp = RandomTempPath::new(); + { + let client: Arc = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); + for b in &blockchain.blocks_rlp() { + let _ = client.import_block(b.clone()); + client.flush_queue(); + client.import_verified_blocks(&IoChannel::disconnected()); + } + let sync = Arc::new(TestSyncProvider::new(SyncConfig { + protocol_version: 65, + num_peers: 120 + })); + + let miner = Arc::new(TestMinerService::default()); + let accounts = Arc::new(TestAccountProvider::new(HashMap::new())); + let server = rpc::RpcServer::new(); + server.add_delegate(EthClient::new(&client, &sync, &accounts, &miner).to_delegate()); + + let url = format!("{}:{}", self.args.flag_jsonrpc_addr, self.args.flag_jsonrpc_port); + let panic_handler = server.start_http(url.as_ref(), "*", 1); + let exit = Arc::new(Condvar::new()); + + let e = exit.clone(); + CtrlC::set_handler(move || { e.notify_all(); }); + + let e = exit.clone(); + panic_handler.on_panic(move |_reason| { e.notify_all(); }); + + let mutex = Mutex::new(()); + let _ = exit.wait(mutex.lock().unwrap()).unwrap(); + } } } diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index b82a20e89..c81f58156 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -23,8 +23,7 @@ mod impls; mod types; mod helpers; -#[cfg(test)] -mod tests; +pub mod tests; pub use self::traits::{Web3, Eth, EthFilter, Personal, Net}; pub use self::impls::*; diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 21085a0fd..7a6340ce1 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -16,8 +16,12 @@ //!TODO: load custom blockchain state and test +pub mod helpers; +#[cfg(test)] mod eth; +#[cfg(test)] mod net; +#[cfg(test)] mod web3; -mod helpers; +#[cfg(test)] mod personal; From a6bd15d333c25f3ac28ee95c3287f7849f34733d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 18 Mar 2016 09:46:13 +0100 Subject: [PATCH 679/753] Fixing compilation --- miner/src/miner.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 660fc55f9..4448b721b 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -137,7 +137,10 @@ impl MinerService for Miner { let mut queue = self.transaction_queue.lock().unwrap(); queue.remove_all( &invalid_transactions.into_iter().collect::>(), - |a: &Address| chain.nonce(a) + |a: &Address| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a), + } ); block }); From 338e5fadb9c87dac08548996fc364196030c4c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 18 Mar 2016 09:54:05 +0100 Subject: [PATCH 680/753] Bumping clippy --- Cargo.lock | 30 +++++++++++++++++------------- Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- json/Cargo.toml | 2 +- miner/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- util/Cargo.toml | 2 +- 8 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79ca26582..8ef60cbc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "parity" version = "1.1.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -96,11 +96,12 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.50" +version = "0.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,7 +210,7 @@ dependencies = [ name = "ethcore" version = "1.1.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.1.0", @@ -235,7 +236,7 @@ dependencies = [ name = "ethcore-rpc" version = "1.1.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.1.0", "ethcore 1.1.0", "ethcore-util 1.1.0", @@ -259,7 +260,7 @@ dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", "chrono 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -303,7 +304,7 @@ dependencies = [ name = "ethminer" version = "1.1.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.1.0", "ethcore-util 1.1.0", @@ -317,7 +318,7 @@ dependencies = [ name = "ethsync" version = "1.1.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.1.0", "ethcore-util 1.1.0", @@ -709,11 +710,6 @@ dependencies = [ "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.3.0" @@ -895,6 +891,14 @@ name = "tiny-keccak" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "toml" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "traitobject" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index fd1d16cff..ac097a05f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ fdlimit = { path = "util/fdlimit" } daemonize = "0.2" number_prefix = "0.2" rpassword = "0.1" -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 1d16cc34a..3683222b1 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -17,7 +17,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } diff --git a/json/Cargo.toml b/json/Cargo.toml index 61599c331..91f8b8431 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -10,7 +10,7 @@ rustc-serialize = "0.3" serde = "0.7.0" serde_json = "0.7.0" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/miner/Cargo.toml b/miner/Cargo.toml index cd56aee9e..2d5bf8e61 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -17,7 +17,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" rayon = "0.3.1" -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } [features] default = [] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 88b69e82c..ca8004728 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -22,7 +22,7 @@ ethminer = { path = "../miner" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 877f4e6c8..91732fea8 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore Date: Fri, 18 Mar 2016 10:14:19 +0100 Subject: [PATCH 681/753] Fixing warnings --- ethcore/src/evm/ext.rs | 1 + ethcore/src/evm/interpreter.rs | 1 + parity/main.rs | 3 ++- util/src/journaldb/archivedb.rs | 4 +++- util/src/journaldb/earlymergedb.rs | 2 ++ util/src/journaldb/overlayrecentdb.rs | 2 ++ util/src/journaldb/refcounteddb.rs | 10 ++++++---- util/src/misc.rs | 2 +- util/src/network/ip_utils.rs | 6 ++++-- 9 files changed, 22 insertions(+), 9 deletions(-) diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index f4172f10a..4986b12c8 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -67,6 +67,7 @@ pub trait Ext { /// Returns Err, if we run out of gas. /// Otherwise returns call_result which contains gas left /// and true if subcall was successfull. + #[cfg_attr(feature="dev", allow(too_many_arguments))] fn call(&mut self, gas: &U256, sender_address: &Address, diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index 7491321cb..b29fc0d41 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -521,6 +521,7 @@ impl Interpreter { Ok(overflowing!(offset.overflowing_add(size.clone()))) } + #[cfg_attr(feature="dev", allow(too_many_arguments))] fn exec_instruction(&self, gas: Gas, params: &ActionParams, diff --git a/parity/main.rs b/parity/main.rs index b8cc2a0f0..c7e534993 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -370,7 +370,7 @@ impl Configuration { fn init_nodes(&self, spec: &Spec) -> Vec { match self.args.flag_bootnodes { - Some(ref x) if x.len() > 0 => x.split(',').map(|s| { + Some(ref x) if !x.is_empty() => x.split(',').map(|s| { Self::normalize_enode(s).unwrap_or_else(|| { die!("{}: Invalid node address format given for a boot node.", s) }) @@ -409,6 +409,7 @@ impl Configuration { ret } + #[cfg_attr(feature="dev", allow(useless_format))] fn client_config(&self) -> ClientConfig { let mut client_config = ClientConfig::default(); match self.args.flag_cache { diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 83a80b7c2..76f0ecc50 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -175,6 +175,8 @@ impl JournalDB for ArchiveDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use hashdb::*; @@ -371,7 +373,7 @@ mod tests { jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); } } - + #[test] fn reopen_fork() { let mut dir = ::std::env::temp_dir(); diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index 7cb00b993..15dcacd6a 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -527,6 +527,8 @@ impl JournalDB for EarlyMergeDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use super::super::traits::JournalDB; diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index efbd26c3b..102e23407 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -358,6 +358,8 @@ impl HashDB for OverlayRecentDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use hashdb::*; diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 590964247..a8c3ff12b 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -28,7 +28,7 @@ use std::env; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// -/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to +/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. @@ -113,7 +113,7 @@ impl JournalDB for RefCountedDB { } fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: + // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, n] => [ ... ] @@ -121,7 +121,7 @@ impl JournalDB for RefCountedDB { // TODO: store last_era, reclaim_period. // when we make a new commit, we journal the inserts and removes. - // for each end_era that we journaled that we are no passing by, + // for each end_era that we journaled that we are no passing by, // we remove all of its removes assuming it is canonical and all // of its inserts otherwise. @@ -147,7 +147,7 @@ impl JournalDB for RefCountedDB { r.append(&self.inserts); r.append(&self.removes); try!(batch.put(&last, r.as_raw())); - + trace!(target: "rcdb", "new journal for time #{}.{} => {}: inserts={:?}, removes={:?}", now, index, id, self.inserts, self.removes); self.inserts.clear(); @@ -194,6 +194,8 @@ impl JournalDB for RefCountedDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use super::super::traits::JournalDB; diff --git a/util/src/misc.rs b/util/src/misc.rs index 76accf93b..159381603 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -88,7 +88,7 @@ pub fn version_data() -> Bytes { u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(); s.append(&v); s.append(&"Parity"); - s.append(&format!("{}", rustc_version())); + s.append(&rustc_version()); s.append(&&Target::os()[0..2]); s.out() } diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs index 9696c601d..b37a47064 100644 --- a/util/src/network/ip_utils.rs +++ b/util/src/network/ip_utils.rs @@ -42,7 +42,7 @@ impl SocketAddrExt for Ipv4Addr { fn is_global_s(&self) -> bool { !self.is_private() && !self.is_loopback() && !self.is_link_local() && - !self.is_broadcast() && !self.is_documentation() + !self.is_broadcast() && !self.is_documentation() } } @@ -216,6 +216,8 @@ fn can_map_external_address_or_fail() { #[test] fn ipv4_properties() { + + #![cfg_attr(feature="dev", allow(too_many_arguments))] fn check(octets: &[u8; 4], unspec: bool, loopback: bool, private: bool, link_local: bool, global: bool, multicast: bool, broadcast: bool, documentation: bool) { @@ -262,7 +264,7 @@ fn ipv6_properties() { assert_eq!(ip.is_global_s(), global); } - // unspec loopbk global + // unspec loopbk global check("::", true, false, true); check("::1", false, true, false); } From 942d38fb134f34f37016120080d531d3a7f1b329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 18 Mar 2016 10:22:00 +0100 Subject: [PATCH 682/753] Removing allow dead_code --- miner/src/transaction_queue.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 71d845e38..0f2ec6ec7 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -306,8 +306,6 @@ impl TransactionQueue { self.minimal_gas_price = min_gas_price; } - // Will be used when rpc merged - #[allow(dead_code)] /// Returns current status for this queue pub fn status(&self) -> TransactionQueueStatus { TransactionQueueStatus { @@ -456,8 +454,6 @@ impl TransactionQueue { self.future.enforce_limit(&mut self.by_hash); } - // Will be used when mining merged - #[allow(dead_code)] /// Returns top transactions from the queue ordered by priority. pub fn top_transactions(&self) -> Vec { self.current.by_priority From 7fb365634a8b25c58d6580b359cb6c471990959f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 18 Mar 2016 10:36:01 +0100 Subject: [PATCH 683/753] Updating gas_limit in test_client generated blocks --- ethcore/src/client/test_client.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 83511b1cc..7e2f59bda 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -111,6 +111,7 @@ impl TestBlockChainClient { header.difficulty = From::from(n); header.parent_hash = self.last_hash.read().unwrap().clone(); header.number = n as BlockNumber; + header.gas_limit = U256::from(1_000_000); let uncles = match with { EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { let mut uncles = RlpStream::new_list(1); From 0dc1ddef9a3620509a7dde77e0d966226522fc5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 18 Mar 2016 13:59:11 +0100 Subject: [PATCH 684/753] Flipping sealing_enabled flag after no requests for sealing_block for some time --- ethcore/src/client/test_client.rs | 6 ++-- miner/src/miner.rs | 58 +++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 83511b1cc..f5c54b705 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -218,11 +218,11 @@ impl BlockChainClient for TestBlockChainClient { } fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> Option { - unimplemented!() + None } - fn try_seal(&self, _block: ClosedBlock, _seal: Vec) -> Result { - unimplemented!() + fn try_seal(&self, block: ClosedBlock, _seal: Vec) -> Result { + Err(block) } fn block_header(&self, id: BlockId) -> Option { diff --git a/miner/src/miner.rs b/miner/src/miner.rs index dc1f9bcff..e90473600 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -34,6 +34,7 @@ pub struct Miner { // for sealing... sealing_enabled: AtomicBool, + sealing_block_last_request: Mutex, sealing_block: Mutex>, gas_floor_target: RwLock, author: RwLock
, @@ -46,6 +47,7 @@ impl Default for Miner { Miner { transaction_queue: Mutex::new(TransactionQueue::new()), sealing_enabled: AtomicBool::new(false), + sealing_block_last_request: Mutex::new(0), sealing_block: Mutex::new(None), gas_floor_target: RwLock::new(U256::zero()), author: RwLock::new(Address::default()), @@ -110,6 +112,8 @@ impl Miner { } } +const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; + impl MinerService for Miner { fn clear_and_reset(&self, chain: &BlockChainClient) { @@ -139,7 +143,17 @@ impl MinerService for Miner { } fn update_sealing(&self, chain: &BlockChainClient) { - if self.sealing_enabled.load(atomic::Ordering::Relaxed) { + let should_disable_sealing = { + let current_no = chain.chain_info().best_block_number; + let last_request = self.sealing_block_last_request.lock().unwrap(); + + current_no - *last_request > SEALING_TIMEOUT_IN_BLOCKS + }; + + if should_disable_sealing { + self.sealing_enabled.store(false, atomic::Ordering::Relaxed); + *self.sealing_block.lock().unwrap() = None; + } else if self.sealing_enabled.load(atomic::Ordering::Relaxed) { self.prepare_sealing(chain); } } @@ -147,9 +161,10 @@ impl MinerService for Miner { fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { if self.sealing_block.lock().unwrap().is_none() { self.sealing_enabled.store(true, atomic::Ordering::Relaxed); - // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. + self.prepare_sealing(chain); } + *self.sealing_block_last_request.lock().unwrap() = chain.chain_info().best_block_number; &self.sealing_block } @@ -228,3 +243,42 @@ impl MinerService for Miner { self.update_sealing(chain); } } + +#[cfg(test)] +mod tests { + + use MinerService; + use super::{Miner}; + use ethcore::client::{TestBlockChainClient, EachBlockWith}; + + // TODO [ToDr] To uncomment client is cleaned from mining stuff. + #[ignore] + #[test] + fn should_prepare_block_to_seal() { + // given + let client = TestBlockChainClient::default(); + let miner = Miner::default(); + + // when + let res = miner.sealing_block(&client); + + // then + assert!(res.lock().unwrap().is_some(), "Expected closed block"); + } + + #[test] + fn should_reset_seal_after_couple_of_blocks() { + // given + let client = TestBlockChainClient::default(); + let miner = Miner::default(); + let res = miner.sealing_block(&client); + // TODO [ToDr] Uncomment after fixing TestBlockChainClient + // assert!(res.lock().unwrap().is_some(), "Expected closed block"); + + // when + client.add_blocks(10, EachBlockWith::Uncle); + + // then + assert!(res.lock().unwrap().is_none(), "Expected to remove sealed block"); + } +} From 7d77324765dd0b4f632b80d26b6774c9fd7b244a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 18 Mar 2016 14:22:25 +0100 Subject: [PATCH 685/753] BlockGasLimit taken from push_transaction result --- ethcore/src/client/client.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 2c011047d..c62364dce 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -419,36 +419,28 @@ impl BlockChainClient for Client where V: Verifier { // Add transactions let block_number = b.block().header().number(); let min_tx_gas = U256::from(self.engine.schedule(&b.env_info()).tx_gas); - let gas_limit = *b.block().header().gas_limit(); - let mut gas_left = gas_limit; let mut invalid_transactions = HashSet::new(); for tx in transactions { - // Stop early if we are sure that no other transaction will be included - if gas_left < min_tx_gas { - break; - } - - // TODO [todr] It seems that calculating gas_left here doesn't look nice. After moving this function - // to miner crate we should consider rewriting this logic in some better way. - if tx.gas > gas_left { - trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", tx.hash()); - continue; - } - // Push transaction to block let hash = tx.hash(); let import = b.push_transaction(tx, None); + match import { + Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => { + trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); + // Exit early if gas left is smaller then min_tx_gas + if gas_limit - gas_used < min_tx_gas { + break; + } + }, Err(e) => { invalid_transactions.insert(hash); trace!(target: "miner", "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", block_number, hash, e); }, - Ok(receipt) => { - gas_left = gas_limit - receipt.gas_used; - } + _ => {} } } From ae3e6d7fe8214755f8a77540e635ae529008b452 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 18:08:28 +0100 Subject: [PATCH 686/753] fixed name of rpctest executable in rpctest --help --- parity/rpctest.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/rpctest.rs b/parity/rpctest.rs index d972a779e..fc4e2983f 100644 --- a/parity/rpctest.rs +++ b/parity/rpctest.rs @@ -47,8 +47,8 @@ Parity rpctest client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity --json --name [options] - parity --help + rpctest --json --name [options] + rpctest --help Options: --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API From 79b8dd829d07cccf644b96db76a03a6770d7d8ff Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 18:16:22 +0100 Subject: [PATCH 687/753] fixed compilation with --release flag --- parity/rpctest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/rpctest.rs b/parity/rpctest.rs index fc4e2983f..4fd31b134 100644 --- a/parity/rpctest.rs +++ b/parity/rpctest.rs @@ -36,7 +36,7 @@ use ethcore::pod_state::PodState; use ethcore::ethereum; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use devtools::RandomTempPath; -use util::io::IoChannel; +use util::IoChannel; use rpc::v1::tests::helpers::{TestSyncProvider, Config as SyncConfig, TestMinerService, TestAccountProvider}; use rpc::v1::{Eth, EthClient}; use util::panics::MayPanic; From 3b8c6a1ab2df30580c6f627c8b7dcc7e5f6454e9 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 19:08:57 +0100 Subject: [PATCH 688/753] linear -> pricing --- ethcore/res/ethereum/frontier.json | 8 +++---- ethcore/res/ethereum/frontier_like_test.json | 8 +++---- ethcore/res/ethereum/frontier_test.json | 8 +++---- ethcore/res/ethereum/homestead_test.json | 8 +++---- ethcore/res/ethereum/morden.json | 8 +++---- ethcore/res/ethereum/olympic.json | 8 +++---- ethcore/res/null_morden.json | 8 +++---- json/src/spec/account.rs | 2 +- json/src/spec/builtin.rs | 23 +++++++++++++++++--- json/src/spec/spec.rs | 8 +++---- 10 files changed, 53 insertions(+), 36 deletions(-) diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index cd66ad3f1..7a1662d8c 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -33,10 +33,10 @@ "enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@parity-node-zero.ethcore.io:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, "3282791d6fd713f1e94f4bfd565eaa78b3a0599d": { "balance": "1337000000000000000000" }, diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index ebfbc2383..803e593be 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } } } } diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index 227ad1bc3..f1a75881a 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } } } } diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index 1fb5dff80..8f13eb042 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } } } } diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index e9f8e0e99..a5230acf4 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -29,10 +29,10 @@ "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index b3dfc1ed8..872877429 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -26,10 +26,10 @@ "gasLimit": "0x2fefd8" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, diff --git a/ethcore/res/null_morden.json b/ethcore/res/null_morden.json index 46507ff95..49795c337 100644 --- a/ethcore/res/null_morden.json +++ b/ethcore/res/null_morden.json @@ -26,10 +26,10 @@ "gasLimit": "0x2fefd8" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/json/src/spec/account.rs b/json/src/spec/account.rs index 8c98f89d9..f4cce3fc8 100644 --- a/json/src/spec/account.rs +++ b/json/src/spec/account.rs @@ -36,7 +36,7 @@ mod tests { fn account_deserialization() { let s = r#"{ "balance": "1", - "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } + "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }"#; let _deserialized: Account = serde_json::from_str(s).unwrap(); // TODO: validate all fields diff --git a/json/src/spec/builtin.rs b/json/src/spec/builtin.rs index f49367ecb..24f83b1d6 100644 --- a/json/src/spec/builtin.rs +++ b/json/src/spec/builtin.rs @@ -16,18 +16,35 @@ //! Spec builtin deserialization. -/// Linear builin options. +use serde::de::{Deserialize, Deserializer}; + +/// Linear pricing. #[derive(Debug, PartialEq, Deserialize)] pub struct Linear { base: u64, word: u64, } +/// Pricing variants. +#[derive(Debug, PartialEq)] +pub enum Pricing { + /// Linear pricing. + Linear(Linear), +} + +impl Deserialize for Pricing { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + Deserialize::deserialize(deserializer).map(Pricing::Linear) + } +} + + /// Spec builtin. #[derive(Debug, PartialEq, Deserialize)] pub struct Builtin { name: String, - linear: Linear, + pricing: Pricing, } #[cfg(test)] @@ -39,7 +56,7 @@ mod tests { fn builtin_deserialization() { let s = r#"{ "name": "ecrecover", - "linear": { "base": 3000, "word": 0 } + "pricing": { "base": 3000, "word": 0 } }"#; let _deserialized: Builtin = serde_json::from_str(s).unwrap(); // TODO: validate all fields diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs index 79662b19a..0d17d0829 100644 --- a/json/src/spec/spec.rs +++ b/json/src/spec/spec.rs @@ -71,10 +71,10 @@ mod tests { "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } }"#; From 1c9cc6167db33d507fdd3413fc44057573aeb486 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 19:16:46 +0100 Subject: [PATCH 689/753] updated rpc helpers docs --- rpc/src/v1/tests/helpers/account_provider.rs | 3 +++ rpc/src/v1/tests/helpers/external_miner.rs | 1 + rpc/src/v1/tests/helpers/miner_service.rs | 5 +++++ rpc/src/v1/tests/helpers/sync_provider.rs | 7 +++++++ 4 files changed, 16 insertions(+) diff --git a/rpc/src/v1/tests/helpers/account_provider.rs b/rpc/src/v1/tests/helpers/account_provider.rs index ce5b76b44..9cbf853ae 100644 --- a/rpc/src/v1/tests/helpers/account_provider.rs +++ b/rpc/src/v1/tests/helpers/account_provider.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Test implementation of account provider. + use std::sync::RwLock; use std::collections::HashMap; use std::io; @@ -42,6 +44,7 @@ impl TestAccount { /// Test account provider. pub struct TestAccountProvider { accounts: RwLock>, + /// Added accounts passwords. pub adds: RwLock>, } diff --git a/rpc/src/v1/tests/helpers/external_miner.rs b/rpc/src/v1/tests/helpers/external_miner.rs index a5111b302..ef3714440 100644 --- a/rpc/src/v1/tests/helpers/external_miner.rs +++ b/rpc/src/v1/tests/helpers/external_miner.rs @@ -26,6 +26,7 @@ pub struct TestExternalMiner { } impl TestExternalMiner { + /// Creates new external miner. pub fn new(hashrates: Arc>>) -> Self { TestExternalMiner { hashrates: hashrates, diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 44b94ac14..bc8d35f46 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Test implementation of miner service. + use util::{Address, H256, Bytes}; use util::standard::*; use ethcore::error::Error; @@ -22,8 +24,11 @@ use ethcore::block::ClosedBlock; use ethcore::transaction::SignedTransaction; use ethminer::{MinerService, MinerStatus, AccountDetails}; +/// Test miner service. pub struct TestMinerService { + /// Imported transactions. pub imported_transactions: RwLock>, + /// Latest closed block. pub latest_closed_block: Mutex>, } diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index 5b4b5b099..222c4c7b9 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -14,15 +14,22 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Test implementation of SyncProvider. + use ethsync::{SyncProvider, SyncStatus, SyncState}; use std::sync::{RwLock}; +/// TestSyncProvider config. pub struct Config { + /// Protocol version. pub protocol_version: u8, + /// Number of peers. pub num_peers: usize, } +/// Test sync provider. pub struct TestSyncProvider { + /// Sync status. pub status: RwLock, } From 839cecd2daae568276f82422ae50149cc254917e Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 19:31:31 +0100 Subject: [PATCH 690/753] fixed od builting parsing --- ethcore/src/builtin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 5589a2525..fbf123ec7 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -19,7 +19,7 @@ use crypto::sha2::Sha256; use crypto::ripemd160::Ripemd160; use crypto::digest::Digest; -/// Definition of a contract whose implementation is built-in. +/// Definition of a contract whose implementation is built-in. pub struct Builtin { /// The gas cost of running this built-in for the given size of input data. pub cost: Box U256>, // TODO: U256 should be bignum. @@ -63,11 +63,11 @@ impl Builtin { /// Create a builtin from JSON. /// - /// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`. + /// JSON must be of the form `{ "name": "identity", "pricing": {"base": 10, "word": 20} }`. pub fn from_json(json: &Json) -> Option { // NICE: figure out a more convenient means of handing errors here. if let Json::String(ref name) = json["name"] { - if let Json::Object(ref o) = json["linear"] { + if let Json::Object(ref o) = json["pricing"] { if let Json::U64(ref word) = o["word"] { if let Json::U64(ref base) = o["base"] { return Self::from_named_linear(&name[..], *base as usize, *word as usize); From e4ec80941c171a6687c63b6e23e8fb7eaf74c48b Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 20:17:25 +0100 Subject: [PATCH 691/753] fixed failing builin test --- ethcore/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index fbf123ec7..0e857335e 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -274,7 +274,7 @@ fn from_named_linear() { #[test] fn from_json() { - let text = "{ \"name\": \"identity\", \"linear\": {\"base\": 10, \"word\": 20} }"; + let text = "{ \"name\": \"identity\", \"pricing\": {\"base\": 10, \"word\": 20} }"; let json = Json::from_str(text).unwrap(); let b = Builtin::from_json(&json).unwrap(); assert_eq!((*b.cost)(0), U256::from(10)); From 48be70e4a8789152f764449a6de574fbc0d93245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 18 Mar 2016 20:45:07 +0100 Subject: [PATCH 692/753] Fixing ethminer doctest --- miner/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index b79a13e24..ca25e3993 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -45,7 +45,6 @@ //! assert_eq!(miner.status().transactions_in_pending_queue, 0); //! //! // Check block for sealing -//! miner.prepare_sealing(client.deref()); //! assert!(miner.sealing_block(client.deref()).lock().unwrap().is_some()); //! } //! ``` From 79aa8570d0fd6f3293a21fe54a9a9892312efba3 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 22:54:36 +0100 Subject: [PATCH 693/753] pricing { linear: {} } --- ethcore/res/ethereum/frontier.json | 8 ++++---- ethcore/res/ethereum/frontier_like_test.json | 8 ++++---- ethcore/res/ethereum/frontier_test.json | 8 ++++---- ethcore/res/ethereum/homestead_test.json | 8 ++++---- ethcore/res/ethereum/morden.json | 8 ++++---- ethcore/res/ethereum/olympic.json | 8 ++++---- ethcore/res/null_morden.json | 8 ++++---- ethcore/src/builtin.rs | 10 ++++++---- json/src/spec/account.rs | 2 +- json/src/spec/builtin.rs | 15 +++------------ json/src/spec/spec.rs | 8 ++++---- 11 files changed, 42 insertions(+), 49 deletions(-) diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index 7a1662d8c..8f9209179 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -33,10 +33,10 @@ "enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@parity-node-zero.ethcore.io:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "3282791d6fd713f1e94f4bfd565eaa78b3a0599d": { "balance": "1337000000000000000000" }, diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 803e593be..49b39cde7 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, } } diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index f1a75881a..79f47b2e6 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, } } diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index 8f13eb042..0f0e630dd 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } } } diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index a5230acf4..2cf4785db 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -29,10 +29,10 @@ "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index 872877429..365a8167c 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -26,10 +26,10 @@ "gasLimit": "0x2fefd8" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, diff --git a/ethcore/res/null_morden.json b/ethcore/res/null_morden.json index 49795c337..70b48fbdb 100644 --- a/ethcore/res/null_morden.json +++ b/ethcore/res/null_morden.json @@ -26,10 +26,10 @@ "gasLimit": "0x2fefd8" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 0e857335e..2ee8e24b1 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -68,9 +68,11 @@ impl Builtin { // NICE: figure out a more convenient means of handing errors here. if let Json::String(ref name) = json["name"] { if let Json::Object(ref o) = json["pricing"] { - if let Json::U64(ref word) = o["word"] { - if let Json::U64(ref base) = o["base"] { - return Self::from_named_linear(&name[..], *base as usize, *word as usize); + if let Json::Object(ref o) = o["linear"] { + if let Json::U64(ref word) = o["word"] { + if let Json::U64(ref base) = o["base"] { + return Self::from_named_linear(&name[..], *base as usize, *word as usize); + } } } } @@ -274,7 +276,7 @@ fn from_named_linear() { #[test] fn from_json() { - let text = "{ \"name\": \"identity\", \"pricing\": {\"base\": 10, \"word\": 20} }"; + let text = r#"{"name": "identity", "pricing": {"linear": {"base": 10, "word": 20}}}"#; let json = Json::from_str(text).unwrap(); let b = Builtin::from_json(&json).unwrap(); assert_eq!((*b.cost)(0), U256::from(10)); diff --git a/json/src/spec/account.rs b/json/src/spec/account.rs index f4cce3fc8..1440b1bdc 100644 --- a/json/src/spec/account.rs +++ b/json/src/spec/account.rs @@ -36,7 +36,7 @@ mod tests { fn account_deserialization() { let s = r#"{ "balance": "1", - "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } + "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }"#; let _deserialized: Account = serde_json::from_str(s).unwrap(); // TODO: validate all fields diff --git a/json/src/spec/builtin.rs b/json/src/spec/builtin.rs index 24f83b1d6..21f8a2ac1 100644 --- a/json/src/spec/builtin.rs +++ b/json/src/spec/builtin.rs @@ -16,8 +16,6 @@ //! Spec builtin deserialization. -use serde::de::{Deserialize, Deserializer}; - /// Linear pricing. #[derive(Debug, PartialEq, Deserialize)] pub struct Linear { @@ -26,20 +24,13 @@ pub struct Linear { } /// Pricing variants. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Deserialize)] pub enum Pricing { /// Linear pricing. + #[serde(rename="linear")] Linear(Linear), } -impl Deserialize for Pricing { - fn deserialize(deserializer: &mut D) -> Result - where D: Deserializer { - Deserialize::deserialize(deserializer).map(Pricing::Linear) - } -} - - /// Spec builtin. #[derive(Debug, PartialEq, Deserialize)] pub struct Builtin { @@ -56,7 +47,7 @@ mod tests { fn builtin_deserialization() { let s = r#"{ "name": "ecrecover", - "pricing": { "base": 3000, "word": 0 } + "pricing": { "linear": { "base": 3000, "word": 0 } } }"#; let _deserialized: Builtin = serde_json::from_str(s).unwrap(); // TODO: validate all fields diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs index 0d17d0829..2dd4ac486 100644 --- a/json/src/spec/spec.rs +++ b/json/src/spec/spec.rs @@ -71,10 +71,10 @@ mod tests { "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } }"#; From ef297dbec7ef35cbc3a8d853a2adbbc299e07a04 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 22:57:26 +0100 Subject: [PATCH 694/753] removed warnings by adding missing documentation --- rpc/src/v1/tests/helpers/account_provider.rs | 1 + rpc/src/v1/tests/helpers/external_miner.rs | 1 + rpc/src/v1/tests/helpers/mod.rs | 2 ++ rpc/src/v1/tests/helpers/sync_provider.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/rpc/src/v1/tests/helpers/account_provider.rs b/rpc/src/v1/tests/helpers/account_provider.rs index 9cbf853ae..614aba346 100644 --- a/rpc/src/v1/tests/helpers/account_provider.rs +++ b/rpc/src/v1/tests/helpers/account_provider.rs @@ -33,6 +33,7 @@ pub struct TestAccount { } impl TestAccount { + /// Creates new test account. pub fn new(password: &str) -> Self { TestAccount { unlocked: false, diff --git a/rpc/src/v1/tests/helpers/external_miner.rs b/rpc/src/v1/tests/helpers/external_miner.rs index ef3714440..1799c36c5 100644 --- a/rpc/src/v1/tests/helpers/external_miner.rs +++ b/rpc/src/v1/tests/helpers/external_miner.rs @@ -22,6 +22,7 @@ use v1::helpers::ExternalMinerService; /// Test ExternalMinerService; pub struct TestExternalMiner { + /// External miners hashrates. pub hashrates: Arc>> } diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index fc652e7d6..c9db61f6d 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Test rpc services. + mod account_provider; mod sync_provider; mod miner_service; diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index 222c4c7b9..48b4f55a9 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -34,6 +34,7 @@ pub struct TestSyncProvider { } impl TestSyncProvider { + /// Creates new sync provider. pub fn new(config: Config) -> Self { TestSyncProvider { status: RwLock::new(SyncStatus { From bd338a5741d5566fddb25f550f637c4aaaddd24b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 18 Mar 2016 23:49:12 +0100 Subject: [PATCH 695/753] Tracing implemented. TODO: - make it optional; - track output; - usher through to level higher than ExecutionResult. --- ethcore/src/evm/evm.rs | 2 +- ethcore/src/executive.rs | 39 +++++++++++++--- ethcore/src/substate.rs | 97 +++++++++++++++++++++++++++++++++------- 3 files changed, 115 insertions(+), 23 deletions(-) diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index 28eb96f44..c1107f003 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -65,7 +65,7 @@ pub enum Error { /// Evm result. /// -/// Returns gas_left if execution is successfull, otherwise error. +/// Returns gas_left if execution is successful, otherwise error. pub type Result = result::Result; /// Evm interface. diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 782063cb2..9c42f1716 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -41,26 +41,34 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address { pub struct Executed { /// Gas paid up front for execution of transaction. pub gas: U256, + /// Gas used during execution of transaction. pub gas_used: U256, + /// Gas refunded after the execution of transaction. /// To get gas that was required up front, add `refunded` and `gas_used`. pub refunded: U256, + /// Cumulative gas used in current block so far. /// /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` /// /// where `tn` is current transaction. pub cumulative_gas_used: U256, + /// Vector of logs generated by transaction. pub logs: Vec, + /// Addresses of contracts created during execution of transaction. /// Ordered from earliest creation. /// /// eg. sender creates contract A and A in constructor creates contract B /// /// B creation ends first, and it will be the first element of the vector. - pub contracts_created: Vec
+ pub contracts_created: Vec
, + + /// The trace of this transaction. + pub trace: Vec, } /// Transaction execution result. @@ -71,7 +79,7 @@ pub struct Executive<'a> { state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, - depth: usize + depth: usize, } impl<'a> Executive<'a> { @@ -243,13 +251,20 @@ impl<'a> Executive<'a> { // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(); + let mut action = TraceAction::from_call(¶ms); + let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) }; + if let TraceAction::Call(ref mut c) = action { + c.result = res.as_ref().ok().map(|gas_left| c.gas - *gas_left); + } + trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); - self.enact_result(&res, substate, unconfirmed_substate); + + self.enact_result(&res, substate, unconfirmed_substate, action); trace!("exec: new substate={:?}\n", substate); res } else { @@ -278,10 +293,18 @@ impl<'a> Executive<'a> { self.state.new_contract(¶ms.address, prev_bal); } + let mut action = TraceAction::from_create(¶ms); + let created = params.address.clone(); + let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract) }; - self.enact_result(&res, substate, unconfirmed_substate); + + if let TraceAction::Create(ref mut c) = action { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created)); + } + + self.enact_result(&res, substate, unconfirmed_substate, action); res } @@ -326,7 +349,8 @@ impl<'a> Executive<'a> { refunded: U256::zero(), cumulative_gas_used: self.info.gas_used + t.gas, logs: vec![], - contracts_created: vec![] + contracts_created: vec![], + trace: substate.trace, }) }, _ => { @@ -337,12 +361,13 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, contracts_created: substate.contracts_created, + trace: substate.trace, }) }, } } - fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) { + fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, action: TraceAction) { match *result { Err(evm::Error::OutOfGas) | Err(evm::Error::BadJumpDestination {..}) @@ -353,7 +378,7 @@ impl<'a> Executive<'a> { }, Ok(_) | Err(evm::Error::Internal) => { self.state.clear_snapshot(); - substate.accrue(un_substate) + substate.accrue(un_substate, action) } } } diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 57e35ad2e..08905ac1a 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -17,43 +17,110 @@ //! Execution environment substate. use common::*; +#[derive(Debug, Clone)] +pub struct TraceCall { + pub from: Address, + pub to: Address, + pub value: U256, + pub gas: U256, + pub input: Bytes, + pub result: Option, +// pub output: Bytes, +} + +#[derive(Debug, Clone)] +pub struct TraceCreate { + pub from: Address, + pub value: U256, + pub gas: U256, + pub init: Bytes, + pub result: Option<(U256, Address)>, +// pub output: Bytes, +} + +#[derive(Debug, Clone)] +pub enum TraceAction { + Unknown, + Call(TraceCall), + Create(TraceCreate), +} + +#[derive(Debug, Clone)] +pub struct TraceItem { + pub action: TraceAction, + pub subs: Vec, +} + +impl Default for TraceItem { + fn default() -> TraceItem { + TraceItem { + action: TraceAction::Unknown, + subs: vec![], + } + } +} + /// State changes which should be applied in finalize, /// after transaction is fully executed. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Substate { /// Any accounts that have suicided. pub suicides: HashSet
, + /// Any logs. pub logs: Vec, + /// Refund counter of SSTORE nonzero -> zero. pub sstore_clears_count: U256, - /// Created contracts. - pub contracts_created: Vec
-} -impl Default for Substate { - fn default() -> Self { - Substate::new() - } + /// Created contracts. + pub contracts_created: Vec
, + + /// The trace during this execution. + pub trace: Vec, } impl Substate { /// Creates new substate. pub fn new() -> Self { - Substate { - suicides: HashSet::new(), - logs: vec![], - sstore_clears_count: U256::zero(), - contracts_created: vec![] - } + Substate::default() } /// Merge secondary substate `s` into self, accruing each element correspondingly. - pub fn accrue(&mut self, s: Substate) { + pub fn accrue(&mut self, s: Substate, action: TraceAction) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); + self.trace.push(TraceItem { + action: action, + subs: s.trace, + }); + } +} + + + +impl TraceAction { + pub fn from_call(p: &ActionParams) -> TraceAction { + TraceAction::Call(TraceCall { + from: p.sender.clone(), + to: p.address.clone(), + value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, + gas: p.gas.clone(), + input: p.data.clone().unwrap_or(vec![]), + result: None, + }) + } + + pub fn from_create(p: &ActionParams) -> TraceAction { + TraceAction::Create(TraceCreate { + from: p.sender.clone(), + value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, + gas: p.gas.clone(), + init: p.data.clone().unwrap_or(vec![]), + result: None, + }) } } From a76aad2e1218017881f94db8f2ddc73240027cd8 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 18 Mar 2016 23:56:51 +0100 Subject: [PATCH 696/753] fixed invalid json files --- ethcore/res/ethereum/frontier_like_test.json | 2 +- ethcore/res/ethereum/frontier_test.json | 2 +- ethcore/res/ethereum/olympic.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 49b39cde7..376b369c4 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -29,6 +29,6 @@ "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } } } diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index 79f47b2e6..92e8f5877 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -29,6 +29,6 @@ "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } } } diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index 365a8167c..0cc2e6a57 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -29,7 +29,7 @@ "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, From d6f94c4ad7f1e47a854fb47951c1da53259f9636 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 08:31:19 +0100 Subject: [PATCH 697/753] Fix test and first part of optionality. --- ethcore/src/executive.rs | 8 ++++---- ethcore/src/substate.rs | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 9c42f1716..d16bc94d9 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -264,7 +264,7 @@ impl<'a> Executive<'a> { trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); - self.enact_result(&res, substate, unconfirmed_substate, action); + self.enact_result(&res, substate, unconfirmed_substate, Some(action)); trace!("exec: new substate={:?}\n", substate); res } else { @@ -304,7 +304,7 @@ impl<'a> Executive<'a> { c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created)); } - self.enact_result(&res, substate, unconfirmed_substate, action); + self.enact_result(&res, substate, unconfirmed_substate, Some(action)); res } @@ -367,7 +367,7 @@ impl<'a> Executive<'a> { } } - fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, action: TraceAction) { + fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, maybe_action: Option) { match *result { Err(evm::Error::OutOfGas) | Err(evm::Error::BadJumpDestination {..}) @@ -378,7 +378,7 @@ impl<'a> Executive<'a> { }, Ok(_) | Err(evm::Error::Internal) => { self.state.clear_snapshot(); - substate.accrue(un_substate, action) + substate.accrue(un_substate, maybe_action) } } } diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 08905ac1a..9880fcd16 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -87,15 +87,17 @@ impl Substate { } /// Merge secondary substate `s` into self, accruing each element correspondingly. - pub fn accrue(&mut self, s: Substate, action: TraceAction) { + pub fn accrue(&mut self, s: Substate, maybe_action: Option) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); - self.trace.push(TraceItem { - action: action, - subs: s.trace, - }); + if let Some(action) = maybe_action { + self.trace.push(TraceItem { + action: action, + subs: s.trace, + }); + } } } @@ -156,7 +158,7 @@ mod tests { }); sub_state_2.sstore_clears_count = x!(7); - sub_state.accrue(sub_state_2); + sub_state.accrue(sub_state_2, None); assert_eq!(sub_state.contracts_created.len(), 2); assert_eq!(sub_state.sstore_clears_count, x!(12)); assert_eq!(sub_state.suicides.len(), 1); From 906e9b395ec3739db3b3ce11ba6e54f46499a9c8 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 11:02:44 +0100 Subject: [PATCH 698/753] fixed parsing blockchain file, added default account to rpc tests --- ethcore/src/pod_account.rs | 3 ++- json/src/blockchain/account.rs | 2 +- parity/rpctest.rs | 10 +++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 8f38326ca..387679da9 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -82,7 +82,8 @@ impl From for PodAccount { code: a.code.into(), storage: a.storage.into_iter().fold(BTreeMap::new(), |mut acc, (key, value)| { let key: U256 = key.into(); - acc.insert(H256::from(key), value.into()); + let value: U256 = value.into(); + acc.insert(H256::from(key), H256::from(value)); acc }) } diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs index 990c024c7..1c51f2b74 100644 --- a/json/src/blockchain/account.rs +++ b/json/src/blockchain/account.rs @@ -31,7 +31,7 @@ pub struct Account { /// Nonce. pub nonce: Uint, /// Storage. - pub storage: BTreeMap, + pub storage: BTreeMap, } #[cfg(test)] diff --git a/parity/rpctest.rs b/parity/rpctest.rs index 4fd31b134..dba188474 100644 --- a/parity/rpctest.rs +++ b/parity/rpctest.rs @@ -37,9 +37,10 @@ use ethcore::ethereum; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use devtools::RandomTempPath; use util::IoChannel; -use rpc::v1::tests::helpers::{TestSyncProvider, Config as SyncConfig, TestMinerService, TestAccountProvider}; +use rpc::v1::tests::helpers::{TestSyncProvider, Config as SyncConfig, TestMinerService, TestAccountProvider, TestAccount}; use rpc::v1::{Eth, EthClient}; use util::panics::MayPanic; +use util::hash::Address; const USAGE: &'static str = r#" Parity rpctest client. @@ -86,8 +87,9 @@ impl Configuration { process::exit(1); }); - let tests: ethjson::blockchain::Test = serde_json::from_reader(file).unwrap_or_else(|_| { + let tests: ethjson::blockchain::Test = serde_json::from_reader(file).unwrap_or_else(|err| { println!("Invalid json file."); + println!("{:?}", err); process::exit(2); }); @@ -117,7 +119,9 @@ impl Configuration { })); let miner = Arc::new(TestMinerService::default()); - let accounts = Arc::new(TestAccountProvider::new(HashMap::new())); + let mut accs = HashMap::new(); + accs.insert(Address::from(1), TestAccount::new("test")); + let accounts = Arc::new(TestAccountProvider::new(accs)); let server = rpc::RpcServer::new(); server.add_delegate(EthClient::new(&client, &sync, &accounts, &miner).to_delegate()); From 52dbcd8152d30b260442e3db6750112d3b4b32cf Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 11:44:36 +0100 Subject: [PATCH 699/753] rpc tests, now 421 passing / 116 failing --- rpc/src/v1/impls/eth.rs | 3 ++- rpc/src/v1/types/block.rs | 6 ++++-- rpc/src/v1/types/bytes.rs | 9 +-------- rpc/src/v1/types/transaction.rs | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 5cd1b2966..2306f937d 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -103,6 +103,7 @@ impl EthClient timestamp: U256::from(view.timestamp()), difficulty: view.difficulty(), total_difficulty: total_difficulty, + nonce: view.seal().get(1).map_or_else(H64::zero, |r| H64::from_slice(r)), uncles: vec![], transactions: { if include_txs { @@ -111,7 +112,7 @@ impl EthClient BlockTransactions::Hashes(block_view.transaction_hashes()) } }, - extra_data: Bytes::default() + extra_data: Bytes::new(view.extra_data()) }; to_value(&block) }, diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 2457efcf8..a7b75a561 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -63,6 +63,7 @@ pub struct Block { pub difficulty: U256, #[serde(rename="totalDifficulty")] pub total_difficulty: U256, + pub nonce: H64, pub uncles: Vec, pub transactions: BlockTransactions } @@ -78,7 +79,7 @@ mod tests { fn test_serialize_block_transactions() { let t = BlockTransactions::Full(vec![Transaction::default()]); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}]"#); let t = BlockTransactions::Hashes(vec![H256::default()]); let serialized = serde_json::to_string(&t).unwrap(); @@ -104,11 +105,12 @@ mod tests { timestamp: U256::default(), difficulty: U256::default(), total_difficulty: U256::default(), + nonce: H64::default(), uncles: vec![], transactions: BlockTransactions::Hashes(vec![]) }; let serialized = serde_json::to_string(&block).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x00","gasUsed":"0x00","gasLimit":"0x00","extraData":"0x00","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x00","difficulty":"0x00","totalDifficulty":"0x00","uncles":[],"transactions":[]}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x00","gasUsed":"0x00","gasLimit":"0x00","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x00","difficulty":"0x00","totalDifficulty":"0x00","nonce":"0x0000000000000000","uncles":[],"transactions":[]}"#); } } diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 0b14c30e8..8c47806f8 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -20,7 +20,7 @@ use serde::de::Visitor; use util::common::FromHex; /// Wrapper structure around vector of bytes. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Default)] pub struct Bytes(Vec); impl Bytes { @@ -31,13 +31,6 @@ impl Bytes { pub fn to_vec(self) -> Vec { let Bytes(x) = self; x } } -impl Default for Bytes { - fn default() -> Self { - // default serialized value is 0x00 - Bytes(vec![0]) - } -} - impl Serialize for Bytes { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 232cf0bf3..d809d19b4 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -67,7 +67,7 @@ mod tests { fn test_transaction_serialize() { let t = Transaction::default(); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}"#); } } From e5c6579a8cc2eb083aa0128095d0c458be36468a Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 12:23:48 +0100 Subject: [PATCH 700/753] next batch of rpc fixes, 103 still failing --- parity/rpctest.rs | 3 ++- rpc/src/v1/impls/eth.rs | 18 +++++++++--------- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- rpc/src/v1/types/block.rs | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/parity/rpctest.rs b/parity/rpctest.rs index dba188474..6cc747959 100644 --- a/parity/rpctest.rs +++ b/parity/rpctest.rs @@ -38,7 +38,7 @@ use ethcore::client::{BlockChainClient, Client, ClientConfig}; use devtools::RandomTempPath; use util::IoChannel; use rpc::v1::tests::helpers::{TestSyncProvider, Config as SyncConfig, TestMinerService, TestAccountProvider, TestAccount}; -use rpc::v1::{Eth, EthClient}; +use rpc::v1::{Eth, EthClient, EthFilter, EthFilterClient}; use util::panics::MayPanic; use util::hash::Address; @@ -124,6 +124,7 @@ impl Configuration { let accounts = Arc::new(TestAccountProvider::new(accs)); let server = rpc::RpcServer::new(); server.add_delegate(EthClient::new(&client, &sync, &accounts, &miner).to_delegate()); + server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); let url = format!("{}:{}", self.args.flag_jsonrpc_addr, self.args.flag_jsonrpc_port); let panic_handler = server.start_http(url.as_ref(), "*", 1); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2306f937d..9b2588670 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -104,7 +104,7 @@ impl EthClient difficulty: view.difficulty(), total_difficulty: total_difficulty, nonce: view.seal().get(1).map_or_else(H64::zero, |r| H64::from_slice(r)), - uncles: vec![], + uncles: block_view.uncle_hashes(), transactions: { if include_txs { BlockTransactions::Full(block_view.localized_transactions().into_iter().map(From::from).collect()) @@ -230,8 +230,8 @@ impl Eth for EthClient fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| // match - to_value(&take_weak!(self.client).block(BlockId::Hash(hash)) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count())))) + take_weak!(self.client).block(BlockId::Hash(hash)) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).transactions_count())))) } fn block_transaction_count_by_number(&self, params: Params) -> Result { @@ -240,24 +240,24 @@ impl Eth for EthClient BlockNumber::Pending => to_value( &U256::from(take_weak!(self.miner).status().transactions_in_pending_block) ), - _ => to_value(&take_weak!(self.client).block(block_number.into()) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count()))) + _ => take_weak!(self.client).block(block_number.into()) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).transactions_count()))) }) } fn block_uncles_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| - to_value(&take_weak!(self.client).block(BlockId::Hash(hash)) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).uncles_count())))) + take_weak!(self.client).block(BlockId::Hash(hash)) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).uncles_count())))) } fn block_uncles_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { BlockNumber::Pending => to_value(&U256::from(0)), - _ => to_value(&take_weak!(self.client).block(block_number.into()) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).uncles_count()))) + _ => take_weak!(self.client).block(block_number.into()) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).uncles_count()))) }) } diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 22e210392..7f07341bf 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -57,7 +57,7 @@ impl MinerService for TestMinerService { where T: Fn(&Address) -> AccountDetails { unimplemented!(); } /// Returns hashes of transactions currently in pending - fn pending_transactions_hashes(&self) -> Vec { unimplemented!(); } + fn pending_transactions_hashes(&self) -> Vec { vec![] } /// Removes all transactions from the queue and restart mining operation. fn clear_and_reset(&self, _chain: &BlockChainClient) { unimplemented!(); } diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index a7b75a561..ac334dd2b 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -64,7 +64,7 @@ pub struct Block { #[serde(rename="totalDifficulty")] pub total_difficulty: U256, pub nonce: H64, - pub uncles: Vec, + pub uncles: Vec, pub transactions: BlockTransactions } From 1bfcbca8af3ce08be7687c54d5d4015cc397463d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 12:54:34 +0100 Subject: [PATCH 701/753] Add doumentation, make tracing optional and expose at OpenBlock level. --- ethcore/src/block.rs | 42 ++++++++++++------ ethcore/src/client/client.rs | 1 + ethcore/src/common.rs | 3 +- ethcore/src/ethereum/ethash.rs | 4 +- ethcore/src/executive.rs | 53 +++++++++++----------- ethcore/src/lib.rs | 1 + ethcore/src/state.rs | 16 +++++-- ethcore/src/substate.rs | 67 +++++++--------------------- ethcore/src/trace.rs | 81 ++++++++++++++++++++++++++++++++++ 9 files changed, 169 insertions(+), 99 deletions(-) create mode 100644 ethcore/src/trace.rs diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d4aa35445..5645989eb 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -24,7 +24,6 @@ use state::*; use verification::PreverifiedBlock; /// A block, encoded as it is on the block chain. -// TODO: rename to Block #[derive(Default, Debug, Clone)] pub struct Block { /// The header of this block. @@ -76,8 +75,6 @@ impl Decodable for Block { } /// Internal type for a block's common elements. -// TODO: rename to ExecutedBlock -// TODO: use BareBlock #[derive(Debug)] pub struct ExecutedBlock { base: Block, @@ -85,6 +82,7 @@ pub struct ExecutedBlock { receipts: Vec, transactions_set: HashSet, state: State, + traces: Option>, } /// A set of references to `ExecutedBlock` fields that are publicly accessible. @@ -99,11 +97,21 @@ pub struct BlockRefMut<'a> { pub receipts: &'a Vec, /// State. pub state: &'a mut State, + /// Traces. + pub traces: &'a Option>, } impl ExecutedBlock { /// Create a new block from the given `state`. - fn new(state: State) -> ExecutedBlock { ExecutedBlock { base: Default::default(), receipts: Default::default(), transactions_set: Default::default(), state: state } } + fn new(state: State, tracing: bool) -> ExecutedBlock { + ExecutedBlock { + base: Default::default(), + receipts: Default::default(), + transactions_set: Default::default(), + state: state, + traces: if tracing {Some(Vec::new())} else {None}, + } + } /// Get a structure containing individual references to all public fields. pub fn fields(&mut self) -> BlockRefMut { @@ -113,6 +121,7 @@ impl ExecutedBlock { uncles: &self.base.uncles, state: &mut self.state, receipts: &self.receipts, + traces: &self.traces, } } } @@ -134,6 +143,9 @@ pub trait IsBlock { /// Get all information on receipts in this block. fn receipts(&self) -> &Vec { &self.block().receipts } + /// Get all information concerning transaction tracing in this block. + fn traces(&self) -> &Option> { &self.block().traces } + /// Get all uncles in this block. fn uncles(&self) -> &Vec
{ &self.block().base.uncles } } @@ -171,9 +183,9 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new(engine: &'x Engine, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self { + pub fn new(engine: &'x Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self { let mut r = OpenBlock { - block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), + block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing), engine: engine, last_hashes: last_hashes, }; @@ -249,11 +261,13 @@ impl<'x> OpenBlock<'x> { pub fn push_transaction(&mut self, t: SignedTransaction, h: Option) -> Result<&Receipt, Error> { let env_info = self.env_info(); // info!("env_info says gas_used={}", env_info.gas_used); - match self.block.state.apply(&env_info, self.engine, &t) { - Ok(receipt) => { + match self.block.state.apply(&env_info, self.engine, &t, self.block.traces.is_some()) { + Ok(outcome) => { self.block.transactions_set.insert(h.unwrap_or_else(||t.hash())); self.block.base.transactions.push(t); - self.block.receipts.push(receipt); + let t = outcome.trace; + self.block.traces.as_mut().map(|traces| traces.push(t.expect("self.block.traces.is_some(): so we must be tracing: qed"))); + self.block.receipts.push(outcome.receipt); Ok(&self.block.receipts.last().unwrap()) } Err(x) => Err(From::from(x)) @@ -340,6 +354,8 @@ impl IsBlock for SealedBlock { /// Enact the block given by block header, transactions and uncles pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { + let tracing = true; // TODO: make param + { if ::log::max_log_level() >= ::log::LogLevel::Trace { let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce()); @@ -347,7 +363,7 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } } - let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone()); + let mut b = OpenBlock::new(engine, tracing, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone()); b.set_difficulty(*header.difficulty()); b.set_gas_limit(*header.gas_limit()); b.set_timestamp(header.timestamp()); @@ -391,7 +407,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); + let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = b.close(); let _ = b.seal(engine.deref(), vec![]); } @@ -405,7 +421,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); - let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close().seal(engine.deref(), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -430,7 +446,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); - let mut open_block = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]); + let mut open_block = OpenBlock::new(engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]); let mut uncle1_header = Header::new(); uncle1_header.extra_data = b"uncle1".to_vec(); let mut uncle2_header = Header::new(); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c62364dce..4a52429f6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -398,6 +398,7 @@ impl BlockChainClient for Client where V: Verifier { let mut b = OpenBlock::new( engine, + false, // TODO: this will need to be parameterised once we want to do immediate mining insertion. self.state_db.lock().unwrap().spawn(), match self.chain.block_header(&h) { Some(ref x) => x, None => {return None} }, self.build_last_hashes(h.clone()), diff --git a/ethcore/src/common.rs b/ethcore/src/common.rs index 5235e9f58..e91501217 100644 --- a/ethcore/src/common.rs +++ b/ethcore/src/common.rs @@ -25,4 +25,5 @@ pub use account::*; pub use transaction::*; pub use log_entry::*; pub use receipt::*; -pub use action_params::*; \ No newline at end of file +pub use action_params::*; +pub use trace::*; \ No newline at end of file diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 406777251..6f854921d 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -299,7 +299,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); + let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -312,7 +312,7 @@ mod tests { let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); + let mut b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let mut uncle = Header::new(); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); uncle.author = uncle_author.clone(); diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index d16bc94d9..28f963d65 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -68,7 +68,7 @@ pub struct Executed { pub contracts_created: Vec
, /// The trace of this transaction. - pub trace: Vec, + pub trace: Option, } /// Transaction execution result. @@ -85,22 +85,21 @@ pub struct Executive<'a> { impl<'a> Executive<'a> { /// Basic constructor. pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine) -> Self { - Executive::new_with_depth(state, info, engine, 0) - } - - /// Populates executive from parent properties. Increments executive depth. - pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { - Executive::new_with_depth(state, info, engine, depth + 1) - } - - /// Helper constructor. Should be used to create `Executive` with desired depth. - /// Private. - fn new_with_depth(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { Executive { state: state, info: info, engine: engine, - depth: depth + depth: 0, + } + } + + /// Populates executive from parent properties. Increments executive depth. + pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, parent_depth: usize) -> Self { + Executive { + state: state, + info: info, + engine: engine, + depth: parent_depth + 1, } } @@ -110,7 +109,7 @@ impl<'a> Executive<'a> { } /// This funtion should be used to execute transaction. - pub fn transact(&'a mut self, t: &SignedTransaction) -> Result { + pub fn transact(&'a mut self, t: &SignedTransaction, tracing: bool) -> Result { let sender = try!(t.sender()); let nonce = self.state.nonce(&sender); @@ -151,7 +150,7 @@ impl<'a> Executive<'a> { self.state.inc_nonce(&sender); self.state.sub_balance(&sender, &U256::from(gas_cost)); - let mut substate = Substate::new(); + let mut substate = Substate::new(tracing); let res = match t.action { Action::Create => { @@ -249,22 +248,22 @@ impl<'a> Executive<'a> { // if destination is a contract, do normal message call // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(); + let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); - let mut action = TraceAction::from_call(¶ms); + let mut action = substate.subtraces.as_ref().map(|_| TraceAction::from_call(¶ms)); let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) }; - if let TraceAction::Call(ref mut c) = action { - c.result = res.as_ref().ok().map(|gas_left| c.gas - *gas_left); + if let Some(TraceAction::Call(ref mut c)) = action { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, vec![])); } trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); - self.enact_result(&res, substate, unconfirmed_substate, Some(action)); + self.enact_result(&res, substate, unconfirmed_substate, action); trace!("exec: new substate={:?}\n", substate); res } else { @@ -282,7 +281,7 @@ impl<'a> Executive<'a> { self.state.snapshot(); // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(); + let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); // create contract and transfer value to it if necessary let prev_bal = self.state.balance(¶ms.address); @@ -293,18 +292,18 @@ impl<'a> Executive<'a> { self.state.new_contract(¶ms.address, prev_bal); } - let mut action = TraceAction::from_create(¶ms); + let mut action = substate.subtraces.as_ref().map(|_| TraceAction::from_create(¶ms)); let created = params.address.clone(); let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract) }; - if let TraceAction::Create(ref mut c) = action { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created)); + if let Some(TraceAction::Create(ref mut c)) = action { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, vec![])); } - self.enact_result(&res, substate, unconfirmed_substate, Some(action)); + self.enact_result(&res, substate, unconfirmed_substate, action); res } @@ -350,7 +349,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + t.gas, logs: vec![], contracts_created: vec![], - trace: substate.trace, + trace: None, }) }, _ => { @@ -361,7 +360,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, contracts_created: substate.contracts_created, - trace: substate.trace, + trace: substate.subtraces.and_then(|mut v| v.pop()), }) }, } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 572cda2fa..ffb4ed905 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -96,6 +96,7 @@ pub mod filter; pub mod header; pub mod service; pub mod log_entry; +pub mod trace; pub mod spec; pub mod transaction; pub mod views; diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index cb54654e6..cad29b678 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -26,8 +26,16 @@ use pod_account::*; use pod_state::PodState; //use state_diff::*; // TODO: uncomment once to_pod() works correctly. +/// Used to return information about an `State::apply` operation. +pub struct ApplyOutcome { + /// The receipt for the applied transaction. + pub receipt: Receipt, + /// The trace for the applied transaction, if None if tracing is disabled. + pub trace: Option, +} + /// Result type for the execution ("application") of a transaction. -pub type ApplyResult = Result; +pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. pub struct State { @@ -209,17 +217,17 @@ impl State { /// Execute a given transaction. /// This will change the state accordingly. - pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction) -> ApplyResult { + pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult { // let old = self.to_pod(); - let e = try!(Executive::new(self, env_info, engine).transact(t)); + let e = try!(Executive::new(self, env_info, engine).transact(t, tracing)); // TODO uncomment once to_pod() works correctly. // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); self.commit(); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); // trace!("Transaction receipt: {:?}", receipt); - Ok(receipt) + Ok(ApplyOutcome{receipt: receipt, trace: e.trace}) } /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 9880fcd16..4a69cf492 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -17,52 +17,9 @@ //! Execution environment substate. use common::*; -#[derive(Debug, Clone)] -pub struct TraceCall { - pub from: Address, - pub to: Address, - pub value: U256, - pub gas: U256, - pub input: Bytes, - pub result: Option, -// pub output: Bytes, -} - -#[derive(Debug, Clone)] -pub struct TraceCreate { - pub from: Address, - pub value: U256, - pub gas: U256, - pub init: Bytes, - pub result: Option<(U256, Address)>, -// pub output: Bytes, -} - -#[derive(Debug, Clone)] -pub enum TraceAction { - Unknown, - Call(TraceCall), - Create(TraceCreate), -} - -#[derive(Debug, Clone)] -pub struct TraceItem { - pub action: TraceAction, - pub subs: Vec, -} - -impl Default for TraceItem { - fn default() -> TraceItem { - TraceItem { - action: TraceAction::Unknown, - subs: vec![], - } - } -} - /// State changes which should be applied in finalize, /// after transaction is fully executed. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Substate { /// Any accounts that have suicided. pub suicides: HashSet
, @@ -76,14 +33,20 @@ pub struct Substate { /// Created contracts. pub contracts_created: Vec
, - /// The trace during this execution. - pub trace: Vec, + /// The trace during this execution or `None` if we're not tracing. + pub subtraces: Option>, } impl Substate { /// Creates new substate. - pub fn new() -> Self { - Substate::default() + pub fn new(tracing: bool) -> Self { + Substate { + suicides: Default::default(), + logs: Default::default(), + sstore_clears_count: Default::default(), + contracts_created: Default::default(), + subtraces: if tracing {Some(vec![])} else {None}, + } } /// Merge secondary substate `s` into self, accruing each element correspondingly. @@ -93,17 +56,16 @@ impl Substate { self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); if let Some(action) = maybe_action { - self.trace.push(TraceItem { + self.subtraces.as_mut().expect("maybe_action is Some: so we must be tracing: qed").push(Trace { action: action, - subs: s.trace, + subs: s.subtraces.expect("maybe_action is Some: so we must be tracing: qed"), }); } } } - - impl TraceAction { + /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a call. pub fn from_call(p: &ActionParams) -> TraceAction { TraceAction::Call(TraceCall { from: p.sender.clone(), @@ -115,6 +77,7 @@ impl TraceAction { }) } + /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a create. pub fn from_create(p: &ActionParams) -> TraceAction { TraceAction::Create(TraceCreate { from: p.sender.clone(), diff --git a/ethcore/src/trace.rs b/ethcore/src/trace.rs new file mode 100644 index 000000000..546404e96 --- /dev/null +++ b/ethcore/src/trace.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Tracing datatypes. +use common::*; + +/// Description of a _call_ action, either a `CALL` operation or a message transction. +#[derive(Debug, Clone)] +pub struct TraceCall { + /// The sending account. + pub from: Address, + /// The destination account. + pub to: Address, + /// The value transferred to the destination account. + pub value: U256, + /// The gas available for executing the call. + pub gas: U256, + /// The input data provided to the call. + pub input: Bytes, + /// The result of the operation; the gas used and the output data of the call. + pub result: Option<(U256, Bytes)>, +} + +/// Description of a _create_ action, either a `CREATE` operation or a create transction. +#[derive(Debug, Clone)] +pub struct TraceCreate { + /// The address of the creator. + pub from: Address, + /// The value with which the new account is endowed. + pub value: U256, + /// The gas available for the creation init code. + pub gas: U256, + /// The init code. + pub init: Bytes, + /// The result of the operation; tuple of the gas used, the address of the newly created account and its code. + /// NOTE: Presently failed operations are not reported so this will always be `Some`. + pub result: Option<(U256, Address, Bytes)>, +// pub output: Bytes, +} + +/// Description of an action that we trace; will be either a call or a create. +#[derive(Debug, Clone)] +pub enum TraceAction { + /// Action isn't yet known. + Unknown, + /// It's a call action. + Call(TraceCall), + /// It's a create action. + Create(TraceCreate), +} + +#[derive(Debug, Clone)] +/// A trace; includes a description of the action being traced and sub traces of each interior action. +pub struct Trace { + /// The action being performed. + pub action: TraceAction, + /// The sub traces for each interior action performed as part of this call. + pub subs: Vec, +} + +impl Default for Trace { + fn default() -> Trace { + Trace { + action: TraceAction::Unknown, + subs: vec![], + } + } +} From 693a3b07398f1bda8ba9c0d024f420ff88bb4e3d Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 12:55:36 +0100 Subject: [PATCH 702/753] fixed failing eth rpc tests --- rpc/src/v1/tests/eth.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 389de103b..a5f318350 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -224,7 +224,7 @@ fn rpc_eth_block_transaction_count_by_hash() { "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } @@ -264,7 +264,7 @@ fn rpc_eth_uncle_count_by_block_hash() { "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } From 203438fb42a09da80c0b055a23fa2c471c26cb6b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 13:07:49 +0100 Subject: [PATCH 703/753] Fix tests. --- ethcore/src/executive.rs | 24 ++++++++++++------------ ethcore/src/externalities.rs | 2 +- ethcore/src/substate.rs | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 28f963d65..bd6199867 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -415,7 +415,7 @@ mod tests { state.add_balance(&sender, &U256::from(0x100u64)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -474,7 +474,7 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -528,7 +528,7 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -580,7 +580,7 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(1024, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); { let mut ex = Executive::new(&mut state, &info, &engine); @@ -641,7 +641,7 @@ mod tests { let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -686,7 +686,7 @@ mod tests { state.init_code(&address, code.clone()); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -723,7 +723,7 @@ mod tests { let executed = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t).unwrap() + ex.transact(&t, false).unwrap() }; assert_eq!(executed.gas, U256::from(100_000)); @@ -756,7 +756,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -787,7 +787,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -820,7 +820,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -853,7 +853,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -883,7 +883,7 @@ mod tests { state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let result = { let mut ex = Executive::new(&mut state, &info, &engine); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index d37bc20fb..6f44bb51c 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -312,7 +312,7 @@ mod tests { TestSetup { state: get_temp_state(), engine: get_test_spec().to_engine().unwrap(), - sub_state: Substate::new(), + sub_state: Substate::new(false), env_info: get_test_env_info() } } diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 4a69cf492..b2056d1b9 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -96,13 +96,13 @@ mod tests { #[test] fn created() { - let sub_state = Substate::new(); + let sub_state = Substate::new(false); assert_eq!(sub_state.suicides.len(), 0); } #[test] fn accrue() { - let mut sub_state = Substate::new(); + let mut sub_state = Substate::new(false); sub_state.contracts_created.push(address_from_u64(1u64)); sub_state.logs.push(LogEntry { address: address_from_u64(1u64), @@ -112,7 +112,7 @@ mod tests { sub_state.sstore_clears_count = x!(5); sub_state.suicides.insert(address_from_u64(10u64)); - let mut sub_state_2 = Substate::new(); + let mut sub_state_2 = Substate::new(false); sub_state_2.contracts_created.push(address_from_u64(2u64)); sub_state_2.logs.push(LogEntry { address: address_from_u64(1u64), From 66837452c23c0a27eb658eafa025f28618d829e9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 13:37:47 +0100 Subject: [PATCH 704/753] Expose tracing all the way to BlockChain; now it's up to blockchain to integrate. --- ethcore/src/block.rs | 20 +++++++++----------- ethcore/src/blockchain/blockchain.rs | 6 ++++++ ethcore/src/client/client.rs | 2 +- ethcore/src/verification/verification.rs | 2 ++ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 5645989eb..144605f89 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -353,9 +353,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { - let tracing = true; // TODO: make param - +pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce()); @@ -373,22 +371,22 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); - enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) + enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let view = BlockView::new(&block.bytes); - enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) + enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { +pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); - Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal()))) + Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes)).seal(engine, header.seal()))) } #[cfg(test)] @@ -428,7 +426,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); - let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap(); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()]).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -461,7 +459,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); engine.spec().ensure_db_good(db.as_hashdb_mut()); - let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, vec![genesis_header.hash()]).unwrap(); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()]).unwrap(); let bytes = e.rlp_bytes(); assert_eq!(bytes, orig_bytes); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 40b01c6f9..7e1a8e23f 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -54,6 +54,9 @@ impl Default for BlockChainConfig { /// Interface for querying blocks by hash and by number. pub trait BlockProvider { + /// True if we store full tracing information for transactions. + fn have_tracing(&self) -> bool; + /// Returns true if the given block is known /// (though not necessarily a part of the canon chain). fn is_known(&self, hash: &H256) -> bool; @@ -177,6 +180,9 @@ impl BlockProvider for BlockChain { self.query_extras_exist(hash, &self.block_details) } + // We do not store tracing information. + fn have_tracing(&self) -> bool { false } + /// Get raw block data fn block(&self, hash: &H256) -> Option { { diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 4a52429f6..614a74798 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -211,7 +211,7 @@ impl Client where V: Verifier { let last_hashes = self.build_last_hashes(header.parent_hash.clone()); let db = self.state_db.lock().unwrap().spawn(); - let enact_result = enact_verified(&block, engine, db, &parent, last_hashes); + let enact_result = enact_verified(&block, engine, self.chain.have_tracing(), db, &parent, last_hashes); if let Err(e) = enact_result { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 60cbed56c..6e79d737e 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -278,6 +278,8 @@ mod tests { } impl BlockProvider for TestBlockChain { + fn have_tracing(&self) -> bool { false } + fn is_known(&self, hash: &H256) -> bool { self.blocks.contains_key(hash) } From 152f132b7b86da8be95dc52c5f964c6863936b76 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 14:10:32 +0100 Subject: [PATCH 705/753] Fix JSONRPC test utils. --- ethcore/src/json_tests/executive.rs | 20 +++++++++++--------- ethcore/src/json_tests/state.rs | 6 +++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index b08257a92..c0c8b3077 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -227,19 +227,21 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { let out_of_gas = test.find("callcreates").map(|_calls| { }).is_none(); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let mut output = vec![]; // execute let (res, callcreates) = { - let mut ex = TestExt::new(&mut state, - &info, - &engine, - 0, - OriginInfo::from(¶ms), - &mut substate, - OutputPolicy::Return(BytesRef::Flexible(&mut output)), - params.address.clone()); + let mut ex = TestExt::new( + &mut state, + &info, + &engine, + 0, + OriginInfo::from(¶ms), + &mut substate, + OutputPolicy::Return(BytesRef::Flexible(&mut output)), + params.address.clone() + ); let evm = engine.vm_factory().create(); let res = evm.exec(params, &mut ex); (res, ex.callcreates) diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index f6b5751a7..4c001007a 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -69,7 +69,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let mut state = state_result.reference_mut(); state.populate_from(pre); state.commit(); - let res = state.apply(&env, engine.deref(), &t); + let res = state.apply(&env, engine.deref(), &t, false); if fail_unless(state.root() == &post_state_root) { println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root); @@ -80,9 +80,9 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { } if let Ok(r) = res { - if fail_unless(logs == r.logs) { + if fail_unless(logs == r.receipt.logs) { println!("!!! {}: Logs mismatch:", name); - println!("Got:\n{:?}", r.logs); + println!("Got:\n{:?}", r.receipt.logs); println!("Expect:\n{:?}", logs); } } From bc5df9c90882c9bb3713a998848a85c164d4dc16 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 14:29:09 +0100 Subject: [PATCH 706/753] added output to execution result --- ethcore/src/executive.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 782063cb2..a00d9a85d 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -60,7 +60,9 @@ pub struct Executed { /// eg. sender creates contract A and A in constructor creates contract B /// /// B creation ends first, and it will be the first element of the vector. - pub contracts_created: Vec
+ pub contracts_created: Vec
, + /// Transaction output. + pub output: Bytes, } /// Transaction execution result. @@ -145,7 +147,7 @@ impl<'a> Executive<'a> { let mut substate = Substate::new(); - let res = match t.action { + let (gas_left, output) = match t.action { Action::Create => { let new_address = contract_address(&sender, &nonce); let params = ActionParams { @@ -159,7 +161,7 @@ impl<'a> Executive<'a> { code: Some(t.data.clone()), data: None, }; - self.create(params, &mut substate) + (self.create(params, &mut substate), vec![]) }, Action::Call(ref address) => { let params = ActionParams { @@ -175,12 +177,12 @@ impl<'a> Executive<'a> { }; // TODO: move output upstream let mut out = vec![]; - self.call(params, &mut substate, BytesRef::Flexible(&mut out)) + (self.call(params, &mut substate, BytesRef::Flexible(&mut out)), out) } }; // finalize here! - Ok(try!(self.finalize(t, substate, res))) + Ok(try!(self.finalize(t, substate, gas_left, output))) } fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy) -> evm::Result { @@ -286,7 +288,7 @@ impl<'a> Executive<'a> { } /// Finalizes the transaction (does refunds and suicides). - fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result) -> ExecutionResult { + fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes) -> ExecutionResult { let schedule = self.engine.schedule(self.info); // refunds from SSTORE nonzero -> zero @@ -326,7 +328,8 @@ impl<'a> Executive<'a> { refunded: U256::zero(), cumulative_gas_used: self.info.gas_used + t.gas, logs: vec![], - contracts_created: vec![] + contracts_created: vec![], + output: output, }) }, _ => { @@ -337,6 +340,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, contracts_created: substate.contracts_created, + output: output, }) }, } From bd7cd68c328aa94aea07bfc1087d6ecca9469309 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 14:35:09 +0100 Subject: [PATCH 707/753] Track depth. --- ethcore/src/executive.rs | 16 ++++++++-------- ethcore/src/substate.rs | 7 ++++--- ethcore/src/trace.rs | 4 ++++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index bd6199867..d7c0ced0a 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -250,20 +250,20 @@ impl<'a> Executive<'a> { // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); - let mut action = substate.subtraces.as_ref().map(|_| TraceAction::from_call(¶ms)); + let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)); let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) }; - if let Some(TraceAction::Call(ref mut c)) = action { + if let Some((TraceAction::Call(ref mut c), _)) = trace_info { c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, vec![])); } trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); - self.enact_result(&res, substate, unconfirmed_substate, action); + self.enact_result(&res, substate, unconfirmed_substate, trace_info); trace!("exec: new substate={:?}\n", substate); res } else { @@ -292,18 +292,18 @@ impl<'a> Executive<'a> { self.state.new_contract(¶ms.address, prev_bal); } - let mut action = substate.subtraces.as_ref().map(|_| TraceAction::from_create(¶ms)); + let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_create(¶ms), self.depth)); let created = params.address.clone(); let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract) }; - if let Some(TraceAction::Create(ref mut c)) = action { + if let Some((TraceAction::Create(ref mut c), _)) = trace_info { c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, vec![])); } - self.enact_result(&res, substate, unconfirmed_substate, action); + self.enact_result(&res, substate, unconfirmed_substate, trace_info); res } @@ -366,7 +366,7 @@ impl<'a> Executive<'a> { } } - fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, maybe_action: Option) { + fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, maybe_info: Option<(TraceAction, usize)>) { match *result { Err(evm::Error::OutOfGas) | Err(evm::Error::BadJumpDestination {..}) @@ -377,7 +377,7 @@ impl<'a> Executive<'a> { }, Ok(_) | Err(evm::Error::Internal) => { self.state.clear_snapshot(); - substate.accrue(un_substate, maybe_action) + substate.accrue(un_substate, maybe_info) } } } diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index b2056d1b9..59f61e433 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -50,14 +50,15 @@ impl Substate { } /// Merge secondary substate `s` into self, accruing each element correspondingly. - pub fn accrue(&mut self, s: Substate, maybe_action: Option) { + pub fn accrue(&mut self, s: Substate, maybe_info: Option<(TraceAction, usize)>) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); - if let Some(action) = maybe_action { + if let Some(info) = maybe_info { self.subtraces.as_mut().expect("maybe_action is Some: so we must be tracing: qed").push(Trace { - action: action, + action: info.0, + depth: info.1, subs: s.subtraces.expect("maybe_action is Some: so we must be tracing: qed"), }); } diff --git a/ethcore/src/trace.rs b/ethcore/src/trace.rs index 546404e96..d2b28b556 100644 --- a/ethcore/src/trace.rs +++ b/ethcore/src/trace.rs @@ -65,6 +65,9 @@ pub enum TraceAction { #[derive(Debug, Clone)] /// A trace; includes a description of the action being traced and sub traces of each interior action. pub struct Trace { + /// The number of EVM execution environments active when this action happened; 0 if it's + /// the outer action of the transaction. + pub depth: usize, /// The action being performed. pub action: TraceAction, /// The sub traces for each interior action performed as part of this call. @@ -74,6 +77,7 @@ pub struct Trace { impl Default for Trace { fn default() -> Trace { Trace { + depth: 0, action: TraceAction::Unknown, subs: vec![], } From 2face3f938209c97c2442ba6d8ac9beb02517c36 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 18:13:14 +0100 Subject: [PATCH 708/753] use ethjson module to load chain json tests --- ethcore/src/block.rs | 2 +- ethcore/src/json_tests/chain.rs | 29 ++++++++++++++--------------- ethcore/src/pod_state.rs | 2 +- json/src/blockchain/account.rs | 1 - json/src/blockchain/block.rs | 6 +++--- json/src/blockchain/blockchain.rs | 11 +++++------ json/src/blockchain/test.rs | 10 ++++++++++ json/src/bytes.rs | 8 ++------ 8 files changed, 36 insertions(+), 33 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d4aa35445..e53cbfd61 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -438,7 +438,7 @@ mod tests { open_block.push_uncle(uncle1_header).unwrap(); open_block.push_uncle(uncle2_header).unwrap(); let b = open_block.close().seal(engine.deref(), vec![]).unwrap(); - + let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 89bd5da2b..5e2d51594 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -16,18 +16,18 @@ use super::test_common::*; use client::{BlockChainClient, Client, ClientConfig}; -use pod_state::*; use block::Block; use ethereum; use tests::helpers::*; use devtools::*; +use spec::Genesis; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); - let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid"); + let tests = ethjson::blockchain::Test.load(json_data).unwrap(); let mut failed = Vec::new(); - for (name, test) in json.as_object().unwrap() { + for (name, blockchain) in tests.deref() { let mut fail = false; { let mut fail_unless = |cond: bool| if !cond && !fail { @@ -39,37 +39,36 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { flush!(" - {}...", name); - let blocks: Vec<(Bytes, bool)> = test["blocks"].as_array().unwrap().iter().map(|e| (xjson!(&e["rlp"]), e.find("blockHeader").is_some())).collect(); let mut spec = match era { ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Homestead => ethereum::new_homestead_test(), }; - let s = PodState::from_json(test.find("pre").unwrap()); - spec.set_genesis_state(s); - spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap()); + + let genesis = Genesis::from(blockchain.genesis()); + let state = From::from(blockchain.pre_state.clone()); + spec.set_genesis_state(state); + spec.overwrite_genesis_params(genesis); assert!(spec.is_state_root_valid()); - let genesis_hash = spec.genesis_header().hash(); - assert_eq!(genesis_hash, H256::from_json(&test.find("genesisBlockHeader").unwrap()["hash"])); let temp = RandomTempPath::new(); { let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); - assert_eq!(client.chain_info().best_block_hash, genesis_hash); - for (b, is_valid) in blocks.into_iter() { + for b in &blockchain.blocks_rlp() { if Block::is_good(&b) { let _ = client.import_block(b.clone()); + client.flush_queue(); + client.import_verified_blocks(&IoChannel::disconnected()); } - client.flush_queue(); - let imported_ok = client.import_verified_blocks(&IoChannel::disconnected()) > 0; - assert_eq!(imported_ok, is_valid); } - fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"])); + fail_unless(client.chain_info().best_block_hash == blockchain.best_block.clone().into()); } } + if !fail { flushln!("ok"); } } + println!("!!! {:?} tests from failed.", failed.len()); failed } diff --git a/ethcore/src/pod_state.rs b/ethcore/src/pod_state.rs index 5782803ef..7ebfed78b 100644 --- a/ethcore/src/pod_state.rs +++ b/ethcore/src/pod_state.rs @@ -21,7 +21,7 @@ use pod_account::*; use ethjson; /// State of all accounts in the system expressed in Plain Old Data. -#[derive(Debug,Clone,PartialEq,Eq,Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct PodState (BTreeMap); impl PodState { diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs index 1c51f2b74..ca69409fc 100644 --- a/json/src/blockchain/account.rs +++ b/json/src/blockchain/account.rs @@ -19,7 +19,6 @@ use std::collections::BTreeMap; use uint::Uint; use bytes::Bytes; -use hash::H256; /// Blockchain test account deserializer. #[derive(Debug, PartialEq, Deserialize, Clone)] diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs index 190102ae5..03522a2c9 100644 --- a/json/src/blockchain/block.rs +++ b/json/src/blockchain/block.rs @@ -24,11 +24,11 @@ use blockchain::transaction::Transaction; #[derive(Debug, PartialEq, Deserialize)] pub struct Block { #[serde(rename="blockHeader")] - header: Header, + header: Option
, rlp: Bytes, - transactions: Vec, + transactions: Option>, #[serde(rename="uncleHeaders")] - uncles: Vec
, + uncles: Option>, } impl Block { diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 4783819e5..98392b983 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -17,6 +17,7 @@ //! Blockchain deserialization. use bytes::Bytes; +use hash::H256; use blockchain::state::State; use blockchain::header::Header; use blockchain::block::Block; @@ -30,7 +31,7 @@ pub struct BlockChain { pub genesis_block: Header, /// Genesis block rlp. #[serde(rename="genesisRLP")] - pub genesis_rlp: Bytes, + pub genesis_rlp: Option, /// Blocks. pub blocks: Vec, /// Post state. @@ -39,14 +40,12 @@ pub struct BlockChain { /// Pre state. #[serde(rename="pre")] pub pre_state: State, + /// Hash of best block. + #[serde(rename="lastblockhash")] + pub best_block: H256 } impl BlockChain { - /// Returns genesis block rlp. - pub fn genesis_rlp(&self) -> Vec { - self.genesis_rlp.clone().into() - } - /// Returns blocks rlp. pub fn blocks_rlp(&self) -> Vec> { self.blocks.iter().map(|block| block.rlp()).collect() diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs index 6f48a8bc6..1a6a63a71 100644 --- a/json/src/blockchain/test.rs +++ b/json/src/blockchain/test.rs @@ -18,6 +18,9 @@ use std::collections::BTreeMap; use std::ops::Deref; +use std::io::Read; +use serde_json; +use serde_json::Error; use blockchain::blockchain::BlockChain; /// Blockchain test deserializer. @@ -31,3 +34,10 @@ impl Deref for Test { &self.0 } } + +impl Test { + /// Loads test from json. + pub fn load(reader: R) -> Result where R: Read { + serde_json::from_reader(reader) + } +} diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 061795b40..6ccae51d7 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -46,12 +46,8 @@ impl Visitor for BytesVisitor { let v = match value.len() { 0 => vec![], 2 if value.starts_with("0x") => vec![], - _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| { - Error::custom(format!("Invalid hex value {}.", value).as_ref()) - })), - _ => try!(FromHex::from_hex(value).map_err(|_| { - Error::custom(format!("Invalid hex value {}.", value).as_ref()) - })) + _ if value.starts_with("0x") => FromHex::from_hex(&value[2..]).unwrap_or(vec![]), + _ => FromHex::from_hex(value).unwrap_or(vec![]), }; Ok(Bytes(v)) } From 7d93fa25336678b6569f119aecaa5efd7bc3095f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 18:37:55 +0100 Subject: [PATCH 709/753] Output stored for calls. --- ethcore/src/executive.rs | 10 ++++--- ethcore/src/externalities.rs | 44 ++++++++++++++++++----------- ethcore/src/json_tests/executive.rs | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index d7c0ced0a..a45577322 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -104,7 +104,7 @@ impl<'a> Executive<'a> { } /// Creates `Externalities` from `Executive`. - pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities { + pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>) -> Externalities { Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output) } @@ -249,15 +249,17 @@ impl<'a> Executive<'a> { // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); - let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)); + let mut trace_output = trace_info.as_ref().map(|_| vec![]); let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) }; if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, vec![])); + if let Some(output) = trace_output { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, output)); + } } trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 6f44bb51c..b0ba67602 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -23,12 +23,12 @@ use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult}; use substate::*; /// Policy for handling output data on `RETURN` opcode. -pub enum OutputPolicy<'a> { +pub enum OutputPolicy<'a, 'b> { /// Return reference to fixed sized output. /// Used for message calls. - Return(BytesRef<'a>), + Return(BytesRef<'a>, Option<&'b mut Bytes>), /// Init new contract as soon as `RETURN` is called. - InitContract + InitContract, } /// Transaction properties that externalities need to know about. @@ -62,18 +62,19 @@ pub struct Externalities<'a> { origin_info: OriginInfo, substate: &'a mut Substate, schedule: Schedule, - output: OutputPolicy<'a> + output: OutputPolicy<'a, 'a> } impl<'a> Externalities<'a> { /// Basic `Externalities` constructor. pub fn new(state: &'a mut State, - env_info: &'a EnvInfo, - engine: &'a Engine, - depth: usize, - origin_info: OriginInfo, - substate: &'a mut Substate, - output: OutputPolicy<'a>) -> Self { + env_info: &'a EnvInfo, + engine: &'a Engine, + depth: usize, + origin_info: OriginInfo, + substate: &'a mut Substate, + output: OutputPolicy<'a, 'a> + ) -> Self { Externalities { state: state, env_info: env_info, @@ -190,20 +191,29 @@ impl<'a> Ext for Externalities<'a> { #[cfg_attr(feature="dev", allow(match_ref_pats))] fn ret(&mut self, gas: &U256, data: &[u8]) -> Result { - match &mut self.output { - &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { + let handle_copy = |to: &mut Option<&mut Bytes>| { + to.as_mut().map(|b| **b = data.to_owned()); + }; + match self.output { + OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { + handle_copy(copy); let len = cmp::min(slice.len(), data.len()); - ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); + unsafe { + ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); + } Ok(*gas) }, - &mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe { + OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => { + handle_copy(copy); vec.clear(); vec.reserve(data.len()); - ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); - vec.set_len(data.len()); + unsafe { + ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); + vec.set_len(data.len()); + } Ok(*gas) }, - &mut OutputPolicy::InitContract => { + OutputPolicy::InitContract => { let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); if return_cost > *gas { return match self.schedule.exceptional_failed_code_deposit { diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index c0c8b3077..7a9426ad3 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -239,7 +239,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { 0, OriginInfo::from(¶ms), &mut substate, - OutputPolicy::Return(BytesRef::Flexible(&mut output)), + OutputPolicy::Return(&mut BytesRef::Flexible(&mut output)), params.address.clone() ); let evm = engine.vm_factory().create(); From 24cb15ef2ea1988bac40085a8cfa364d7a3b5f2e Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 18:38:02 +0100 Subject: [PATCH 710/753] fixed missing import --- ethcore/src/json_tests/chain.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 5e2d51594..a2e6a5659 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -21,10 +21,11 @@ use ethereum; use tests::helpers::*; use devtools::*; use spec::Genesis; +use ethjson; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); - let tests = ethjson::blockchain::Test.load(json_data).unwrap(); + let tests = ethjson::blockchain::Test::load(json_data).unwrap(); let mut failed = Vec::new(); for (name, blockchain) in tests.deref() { From 40f20de7aa22570a2f2f32697d31d284e6326675 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 18:46:28 +0100 Subject: [PATCH 711/753] test ethjson module on travis --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5d6de65c2..f7ac723e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ env: global: # GH_TOKEN - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= - - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" + - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethjson" - ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - KCOV_FEATURES="" - KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov" @@ -70,6 +70,7 @@ after_success: | $KCOV_CMD target/debug/deps/ethsync-* && $KCOV_CMD target/debug/deps/ethcore_rpc-* && $KCOV_CMD target/debug/deps/ethminer-* && + $KCOV_CMD target/debug/deps/ethjson-* && $KCOV_CMD target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && From ab9b8c7bf365c36d4c34990ba552c754407c8c2e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 18:46:41 +0100 Subject: [PATCH 712/753] Output data (code) for creates. --- ethcore/src/executive.rs | 10 ++++++++-- ethcore/src/externalities.rs | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index a45577322..2c1d7b023 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -249,6 +249,8 @@ impl<'a> Executive<'a> { // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); + + // transaction tracing stuff. None if there's no tracing. let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)); let mut trace_output = trace_info.as_ref().map(|_| vec![]); @@ -256,6 +258,7 @@ impl<'a> Executive<'a> { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) }; + // if there's tracing, make up trace_info's result with trace_output and some arithmetic. if let Some((TraceAction::Call(ref mut c), _)) = trace_info { if let Some(output) = trace_output { c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, output)); @@ -295,14 +298,17 @@ impl<'a> Executive<'a> { } let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_create(¶ms), self.depth)); + let mut trace_output = trace_info.as_ref().map(|_| vec![]); let created = params.address.clone(); let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut())) }; if let Some((TraceAction::Create(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, vec![])); + if let Some(output) = trace_output { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, output)); + } } self.enact_result(&res, substate, unconfirmed_substate, trace_info); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index b0ba67602..6e9605354 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -28,7 +28,7 @@ pub enum OutputPolicy<'a, 'b> { /// Used for message calls. Return(BytesRef<'a>, Option<&'b mut Bytes>), /// Init new contract as soon as `RETURN` is called. - InitContract, + InitContract(Option<&'b mut Bytes>), } /// Transaction properties that externalities need to know about. @@ -213,7 +213,7 @@ impl<'a> Ext for Externalities<'a> { } Ok(*gas) }, - OutputPolicy::InitContract => { + OutputPolicy::InitContract(ref mut copy) => { let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); if return_cost > *gas { return match self.schedule.exceptional_failed_code_deposit { @@ -221,6 +221,9 @@ impl<'a> Ext for Externalities<'a> { false => Ok(*gas) } } + + handle_copy(copy); + let mut code = vec![]; code.reserve(data.len()); unsafe { @@ -333,7 +336,7 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); assert_eq!(ext.env_info().number, 100); } @@ -342,7 +345,7 @@ mod tests { fn can_return_block_hash_no_env() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -361,7 +364,7 @@ mod tests { env_info.last_hashes.push(test_hash.clone()); } let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -373,7 +376,7 @@ mod tests { fn can_call_fail_empty() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); let mut output = vec![]; @@ -397,7 +400,7 @@ mod tests { let state = setup.state.reference_mut(); { - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); ext.log(log_topics, &log_data); } @@ -412,7 +415,7 @@ mod tests { let state = setup.state.reference_mut(); { - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); ext.suicide(&refund_account); } From 2d55e08b415b81e83b36a55107d64050b9fe53c4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 19:06:13 +0100 Subject: [PATCH 713/753] Fix for jsontests, --- ethcore/src/json_tests/executive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 7a9426ad3..a1ce290d8 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -75,7 +75,7 @@ impl<'a> TestExt<'a> { depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, - output: OutputPolicy<'a>, + output: OutputPolicy<'a, 'a>, address: Address) -> Self { TestExt { contract_address: contract_address(&address, &state.nonce(&address)), From da027e93cf8e9c33727bfb1ef7634de517da05e4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 19 Mar 2016 20:58:42 +0100 Subject: [PATCH 714/753] Auto detect available port --- ethcore/src/service.rs | 2 +- util/src/network/host.rs | 93 +++++++++++++++++++++---------------- util/src/network/mod.rs | 2 +- util/src/network/service.rs | 21 +++++++-- util/src/network/session.rs | 2 +- util/src/network/tests.rs | 20 ++++---- 6 files changed, 80 insertions(+), 60 deletions(-) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index bcfe7724f..95a891198 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -146,7 +146,7 @@ mod tests { fn it_can_be_started() { let spec = get_test_spec(); let temp_path = RandomTempPath::new(); - let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path()); + let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path()); assert!(service.is_ok()); } } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 02c576424..6baf0cf76 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -105,6 +105,14 @@ impl NetworkConfiguration { config.listen_address = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap()); config } + + /// Create new default configuration for localhost-only connection with random port (usefull for testing) + pub fn new_local() -> NetworkConfiguration { + let mut config = NetworkConfiguration::new(); + config.listen_address = Some(SocketAddr::from_str("127.0.0.1:0").unwrap()); + config.nat_enabled = false; + config + } } // Tokens @@ -269,12 +277,12 @@ pub struct HostInfo { pub protocol_version: u32, /// Client identifier pub client_version: String, - /// TCP connection port. - pub listen_port: u16, /// Registered capabilities (handlers) pub capabilities: Vec, + /// Local address + discovery port + pub local_endpoint: NodeEndpoint, /// Public address + discovery port - public_endpoint: NodeEndpoint, + pub public_endpoint: Option, } impl HostInfo { @@ -307,7 +315,7 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, - tcp_listener: Mutex>, + tcp_listener: Mutex, handshakes: Arc>>, sessions: Arc>>, discovery: Mutex>, @@ -321,13 +329,12 @@ pub struct Host where Message: Send + Sync + Clone { impl Host where Message: Send + Sync + Clone { /// Create a new instance - pub fn new(config: NetworkConfiguration) -> Host { - let listen_address = match config.listen_address { + pub fn new(config: NetworkConfiguration) -> Result, UtilError> { + let mut listen_address = match config.listen_address { None => SocketAddr::from_str("0.0.0.0:30304").unwrap(), Some(addr) => addr, }; - let udp_port = config.udp_port.unwrap_or(listen_address.port()); let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { @@ -342,7 +349,12 @@ impl Host where Message: Send + Sync + Clone { |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; let path = config.config_path.clone(); + // Setup the server socket + let tcp_listener = try!(TcpListener::bind(&listen_address)); + listen_address = SocketAddr::new(listen_address.ip(), try!(tcp_listener.local_addr()).port()); + let udp_port = config.udp_port.unwrap_or(listen_address.port()); let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port }; + let mut host = Host:: { info: RwLock::new(HostInfo { keys: keys, @@ -350,12 +362,12 @@ impl Host where Message: Send + Sync + Clone { nonce: H256::random(), protocol_version: PROTOCOL_VERSION, client_version: version(), - listen_port: 0, capabilities: Vec::new(), - public_endpoint: local_endpoint, // will be replaced by public once it is resolved + public_endpoint: None, + local_endpoint: local_endpoint, }), discovery: Mutex::new(None), - tcp_listener: Mutex::new(None), + tcp_listener: Mutex::new(tcp_listener), handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), @@ -365,14 +377,12 @@ impl Host where Message: Send + Sync + Clone { stats: Arc::new(NetworkStats::default()), pinned_nodes: Vec::new(), }; - let port = listen_address.port(); - host.info.write().unwrap().deref_mut().listen_port = port; let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); for n in boot_nodes { host.add_node(&n); } - host + Ok(host) } pub fn stats(&self) -> Arc { @@ -397,50 +407,50 @@ impl Host where Message: Send + Sync + Clone { self.info.read().unwrap().client_version.clone() } - pub fn client_url(&self) -> String { - format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().public_endpoint.clone())) + pub fn external_url(&self) -> Option { + self.info.read().unwrap().public_endpoint.as_ref().map(|e| format!("{}", Node::new(self.info.read().unwrap().id().clone(), e.clone()))) } - fn init_public_interface(&self, io: &IoContext>) { + pub fn local_url(&self) -> String { + let r = format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().local_endpoint.clone())); + println!("{}", r); + r + } + + fn init_public_interface(&self, io: &IoContext>) -> Result<(), UtilError> { io.clear_timer(INIT_PUBLIC).unwrap(); - let mut tcp_listener = self.tcp_listener.lock().unwrap(); - if tcp_listener.is_some() { - return; + if self.info.read().unwrap().public_endpoint.is_some() { + return Ok(()); } - // public_endpoint in host info contains local adderss at this point - let listen_address = self.info.read().unwrap().public_endpoint.address.clone(); - let udp_port = self.info.read().unwrap().config.udp_port.unwrap_or(listen_address.port()); + let local_endpoint = self.info.read().unwrap().local_endpoint.clone(); let public_address = self.info.read().unwrap().config.public_address.clone(); let public_endpoint = match public_address { None => { - let public_address = select_public_address(listen_address.port()); - let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; + let public_address = select_public_address(local_endpoint.address.port()); + let public_endpoint = NodeEndpoint { address: public_address, udp_port: local_endpoint.udp_port }; if self.info.read().unwrap().config.nat_enabled { match map_external_address(&local_endpoint) { Some(endpoint) => { - info!("NAT mappped to external address {}", endpoint.address); + info!("NAT mapped to external address {}", endpoint.address); endpoint }, - None => local_endpoint + None => public_endpoint } } else { - local_endpoint + public_endpoint } } - Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port } + Some(addr) => NodeEndpoint { address: addr, udp_port: local_endpoint.udp_port } }; - // Setup the server socket - *tcp_listener = Some(TcpListener::bind(&listen_address).unwrap()); - self.info.write().unwrap().public_endpoint = public_endpoint.clone(); - io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); - info!("Public node URL: {}", self.client_url()); + self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone()); + info!("Public node URL: {}", self.external_url().unwrap()); // Initialize discovery. let discovery = { let info = self.info.read().unwrap(); if info.config.discovery_enabled && !info.config.pin { - Some(Discovery::new(&info.keys, listen_address.clone(), public_endpoint, DISCOVERY)) + Some(Discovery::new(&info.keys, public_endpoint.address.clone(), public_endpoint, DISCOVERY)) } else { None } }; @@ -454,6 +464,8 @@ impl Host where Message: Send + Sync + Clone { io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); *self.discovery.lock().unwrap().deref_mut() = Some(discovery); } + try!(io.register_stream(TCP_ACCEPT)); + Ok(()) } fn maintain_network(&self, io: &IoContext>) { @@ -567,7 +579,7 @@ impl Host where Message: Send + Sync + Clone { fn accept(&self, io: &IoContext>) { trace!(target: "network", "Accepting incoming connection"); loop { - let socket = match self.tcp_listener.lock().unwrap().as_ref().unwrap().accept() { + let socket = match self.tcp_listener.lock().unwrap().accept() { Ok(None) => break, Ok(Some((sock, _addr))) => sock, Err(e) => { @@ -861,7 +873,8 @@ impl IoHandler> for Host where Messa fn timeout(&self, io: &IoContext>, token: TimerToken) { match token { IDLE => self.maintain_network(io), - INIT_PUBLIC => self.init_public_interface(io), + INIT_PUBLIC => self.init_public_interface(io).unwrap_or_else(|e| + warn!("Error initializing public interface: {:?}", e)), FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { @@ -945,7 +958,7 @@ impl IoHandler> for Host where Messa } } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), - TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), + TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } } @@ -986,7 +999,7 @@ impl IoHandler> for Host where Messa } } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), - TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), + TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } } @@ -1054,6 +1067,6 @@ fn host_client_url() { let mut config = NetworkConfiguration::new(); let key = h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2"); config.use_secret = Some(key); - let host: Host = Host::new(config); - assert!(host.client_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); + let host: Host = Host::new(config).unwrap(); + assert!(host.local_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); } diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index 50645f2be..29f3d166c 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -56,7 +56,7 @@ //! } //! //! fn main () { -//! let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40412)).expect("Error creating network service"); +//! let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); //! service.register_protocol(Arc::new(MyHandler), "myproto", &[1u8]); //! //! // Wait for quit condition diff --git a/util/src/network/service.rs b/util/src/network/service.rs index 7b9388e85..49957f7e7 100644 --- a/util/src/network/service.rs +++ b/util/src/network/service.rs @@ -28,6 +28,7 @@ use io::*; pub struct NetworkService where Message: Send + Sync + Clone + 'static { io_service: IoService>, host_info: String, + host: Arc>, stats: Arc, panic_handler: Arc } @@ -39,15 +40,16 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat let mut io_service = try!(IoService::>::start()); panic_handler.forward_from(&io_service); - let host = Arc::new(Host::new(config)); + let host = Arc::new(try!(Host::new(config))); let stats = host.stats().clone(); let host_info = host.client_version(); - try!(io_service.register_handler(host)); + try!(io_service.register_handler(host.clone())); Ok(NetworkService { io_service: io_service, host_info: host_info, stats: stats, - panic_handler: panic_handler + panic_handler: panic_handler, + host: host, }) } @@ -71,12 +73,21 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat &mut self.io_service } - /// Returns underlying io service. + /// Returns network statistics. pub fn stats(&self) -> &NetworkStats { &self.stats } -} + /// Returns external url if available. + pub fn external_url(&self) -> Option { + self.host.external_url() + } + + /// Returns external url if available. + pub fn local_url(&self) -> String { + self.host.local_url() + } +} impl MayPanic for NetworkService where Message: Send + Sync + Clone + 'static { fn on_panic(&self, closure: F) where F: OnPanicListener { diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 2f30d7376..7dbcc4229 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -315,7 +315,7 @@ impl Session { .append(&host.protocol_version) .append(&host.client_version) .append(&host.capabilities) - .append(&host.listen_port) + .append(&host.local_endpoint.address.port()) .append(host.id()); self.connection.send_packet(&rlp.out()) } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index f8ef588f6..0493475ce 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -97,21 +97,19 @@ impl NetworkProtocolHandler for TestProtocol { #[test] fn net_service() { - let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40414)).expect("Error creating network service"); + let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); service.register_protocol(Arc::new(TestProtocol::new(false)), "myproto", &[1u8]).unwrap(); } #[test] fn net_connect() { let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_with_port(30354); + let mut config1 = NetworkConfiguration::new_local(); config1.use_secret = Some(key1.secret().clone()); - config1.nat_enabled = false; config1.boot_nodes = vec![ ]; - let mut config2 = NetworkConfiguration::new_with_port(30355); - config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30354", key1.public().hex()) ]; - config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); + let mut config2 = NetworkConfiguration::new_local(); + config2.boot_nodes = vec![ service1.local_url() ]; let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1, false); let handler2 = TestProtocol::register(&mut service2, false); @@ -125,14 +123,12 @@ fn net_connect() { #[test] fn net_disconnect() { let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_with_port(30364); + let mut config1 = NetworkConfiguration::new_local(); config1.use_secret = Some(key1.secret().clone()); - config1.nat_enabled = false; config1.boot_nodes = vec![ ]; - let mut config2 = NetworkConfiguration::new_with_port(30365); - config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30364", key1.public().hex()) ]; - config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); + let mut config2 = NetworkConfiguration::new_local(); + config2.boot_nodes = vec![ service1.local_url() ]; let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1, false); let handler2 = TestProtocol::register(&mut service2, true); @@ -145,7 +141,7 @@ fn net_disconnect() { #[test] fn net_timeout() { - let config = NetworkConfiguration::new_with_port(30346); + let config = NetworkConfiguration::new_local(); let mut service = NetworkService::::start(config).unwrap(); let handler = TestProtocol::register(&mut service, false); while !handler.got_timeout() { From a2fc006ee5ae1412407435a2ebc5bd1bc0c34ca2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 21:02:44 +0100 Subject: [PATCH 715/753] First test. --- ethcore/src/executive.rs | 81 +++++++++++++++++++++++++++++++++++- ethcore/src/externalities.rs | 5 ++- ethcore/src/substate.rs | 2 +- ethcore/src/trace.rs | 8 ++-- 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 2c1d7b023..40c69d97a 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -440,8 +440,8 @@ mod tests { // TODO: just test state root. } - evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int} - fn test_create_contract(factory: Factory) { + evm_test!{test_create_contract_out_of_depth: test_create_contract_out_of_depth_jit, test_create_contract_out_of_depth_int} + fn test_create_contract_out_of_depth(factory: Factory) { // code: // // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? @@ -494,6 +494,83 @@ mod tests { assert_eq!(substate.contracts_created.len(), 0); } + evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int} + fn test_create_contract(factory: Factory) { + // code: + // + // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? + // 60 00 - push 0 + // 52 + // 60 1d - push 29 + // 60 03 - push 3 + // 60 17 - push 17 + // f0 - create + // 60 00 - push 0 + // 55 sstore + // + // other code: + // + // 60 10 - push 16 + // 80 - duplicate first stack item + // 60 0c - push 12 + // 60 00 - push 0 + // 39 - copy current code to memory + // 60 00 - push 0 + // f3 - return + + let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap(); + + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + let address = contract_address(&sender, &U256::zero()); + // TODO: add tests for 'callcreate' + //let next_address = contract_address(&address, &U256::zero()); + let mut params = ActionParams::default(); + params.address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(100_000); + params.code = Some(code.clone()); + params.value = ActionValue::Transfer(U256::from(100)); + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + state.add_balance(&sender, &U256::from(100)); + let info = EnvInfo::default(); + let engine = TestEngine::new(5, factory); + let mut substate = Substate::new(true); + + let gas_left = { + let mut ex = Executive::new(&mut state, &info, &engine); + let output = BytesRef::Fixed(&mut[0u8;0]); + ex.call(params, &mut substate, output).unwrap() + }; + + println!("trace: {:?}", substate.subtraces); + let expected_trace = Some(vec![ Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("cd1722f3947def4cf144679da39c4c32bdc35681"), + to: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), + value: x!(100), + gas: x!(100000), + input: vec![], + result: Some((x!(55248), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Create(TraceCreate { + from: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), + value: x!(23), + gas: x!(67979), + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + result: Some((x!(3224), x!("c6d80f262ae5e0f164e5fde365044d7ada2bfa34"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])), + }), + subs: vec![] + }] + } ]); + assert_eq!(substate.subtraces, expected_trace); + assert_eq!(gas_left, U256::from(44_752)); + } + evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int} fn test_create_contract_value_too_high(factory: Factory) { // code: diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 6e9605354..a6f7e4f36 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -197,6 +197,7 @@ impl<'a> Ext for Externalities<'a> { match self.output { OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { handle_copy(copy); + let len = cmp::min(slice.len(), data.len()); unsafe { ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); @@ -205,6 +206,7 @@ impl<'a> Ext for Externalities<'a> { }, OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => { handle_copy(copy); + vec.clear(); vec.reserve(data.len()); unsafe { @@ -230,8 +232,7 @@ impl<'a> Ext for Externalities<'a> { ptr::copy(data.as_ptr(), code.as_mut_ptr(), data.len()); code.set_len(data.len()); } - let address = &self.origin_info.address; - self.state.init_code(address, code); + self.state.init_code(&self.origin_info.address, code); Ok(*gas - return_cost) } } diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 59f61e433..9e6d0cea2 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -84,7 +84,7 @@ impl TraceAction { from: p.sender.clone(), value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, gas: p.gas.clone(), - init: p.data.clone().unwrap_or(vec![]), + init: p.code.clone().unwrap_or(vec![]), result: None, }) } diff --git a/ethcore/src/trace.rs b/ethcore/src/trace.rs index d2b28b556..1f45e846f 100644 --- a/ethcore/src/trace.rs +++ b/ethcore/src/trace.rs @@ -18,7 +18,7 @@ use common::*; /// Description of a _call_ action, either a `CALL` operation or a message transction. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct TraceCall { /// The sending account. pub from: Address, @@ -35,7 +35,7 @@ pub struct TraceCall { } /// Description of a _create_ action, either a `CREATE` operation or a create transction. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct TraceCreate { /// The address of the creator. pub from: Address, @@ -52,7 +52,7 @@ pub struct TraceCreate { } /// Description of an action that we trace; will be either a call or a create. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum TraceAction { /// Action isn't yet known. Unknown, @@ -62,7 +62,7 @@ pub enum TraceAction { Create(TraceCreate), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] /// A trace; includes a description of the action being traced and sub traces of each interior action. pub struct Trace { /// The number of EVM execution environments active when this action happened; 0 if it's From 718feeccbcc1d191b517b30f4b06005b468d041d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 21:05:18 +0100 Subject: [PATCH 716/753] Fix for JSON tests. --- ethcore/src/json_tests/executive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index a1ce290d8..63638dfb3 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -239,7 +239,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { 0, OriginInfo::from(¶ms), &mut substate, - OutputPolicy::Return(&mut BytesRef::Flexible(&mut output)), + OutputPolicy::Return(&mut BytesRef::Flexible(&mut output), None), params.address.clone() ); let evm = engine.vm_factory().create(); From 521f2a14331e60b0f40f4cd64b31b3b2fada7665 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 21:37:11 +0100 Subject: [PATCH 717/753] implemented eth_call --- ethcore/src/client/client.rs | 25 +++++++++++++++++++++++++ ethcore/src/client/mod.rs | 5 ++++- ethcore/src/client/test_client.rs | 6 ++++++ ethcore/src/views.rs | 3 +++ rpc/src/v1/impls/eth.rs | 20 ++++++++++++++++++++ util/bigint/src/uint.rs | 11 +++++++++++ 6 files changed, 69 insertions(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c62364dce..a0538d8de 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -37,6 +37,8 @@ use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; +use env_info::EnvInfo; +use executive::{Executive, Executed}; pub use blockchain::CacheSize as BlockChainCacheSize; /// General block status @@ -385,6 +387,29 @@ impl Client where V: Verifier { } impl BlockChainClient for Client where V: Verifier { + fn call(&self, t: &SignedTransaction) -> Result { + let header = self.block_header(BlockId::Latest).unwrap(); + let view = HeaderView::new(&header); + let last_hashes = self.build_last_hashes(view.hash()); + let env_info = EnvInfo { + number: view.number(), + author: view.author(), + timestamp: view.timestamp(), + difficulty: view.difficulty(), + last_hashes: last_hashes, + gas_used: U256::zero(), + gas_limit: U256::max_value(), + }; + // that's just a copy of the state. + let mut state = self.state(); + let sender = try!(t.sender()); + let balance = state.balance(&sender); + // give the sender max balance + state.sub_balance(&sender, &balance); + state.add_balance(&sender, &U256::max_value()); + Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t) + } + // TODO [todr] Should be moved to miner crate eventually. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result { block.try_seal(self.engine.deref().deref(), seal) diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 198e918f7..4a3208eb8 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -37,7 +37,8 @@ use header::BlockNumber; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; -use error::{ImportResult}; +use error::{ImportResult, Error}; +use executive::Executed; /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -118,5 +119,7 @@ pub trait BlockChainClient : Sync + Send { /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result; + /// Makes a non-persistent transaction call. + fn call(&self, t: &SignedTransaction) -> Result; } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 9150a5f55..5d51368de 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -29,6 +29,8 @@ use error::{ImportResult}; use block_queue::BlockQueueInfo; use block::{SealedBlock, ClosedBlock}; +use executive::Executed; +use error::Error; /// Test client. pub struct TestBlockChainClient { @@ -182,6 +184,10 @@ impl TestBlockChainClient { } impl BlockChainClient for TestBlockChainClient { + fn call(&self, t: &SignedTransaction) -> Result { + unimplemented!() + } + fn block_total_difficulty(&self, _id: BlockId) -> Option { Some(U256::zero()) } diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 745cbff2c..11e26eb5f 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -256,6 +256,9 @@ impl<'a> HeaderView<'a> { } } + /// Returns header hash. + pub fn hash(&self) -> H256 { self.sha3() } + /// Returns raw rlp. pub fn rlp(&self) -> &Rlp<'a> { &self.rlp } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 5cd1b2966..7fa12295d 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -397,6 +397,26 @@ impl Eth for EthClient } }) } + + fn call(&self, params: Params) -> Result { + from_params::<(TransactionRequest, BlockNumber)>(params) + .and_then(|(transaction_request, _block_number)| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&transaction_request.from) { + Ok(secret) => { + let client = take_weak!(self.client); + + let transaction: EthTransaction = transaction_request.into(); + let signed_transaction = transaction.sign(&secret); + + to_value(&client.call(&signed_transaction) + .map(|e| Bytes::new(e.output)) + .unwrap_or(Bytes::default())) + }, + Err(_) => { to_value(&Bytes::default()) } + } + }) + } } /// Eth filter rpc implementation. diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index d185750c2..7bc6007ed 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -490,6 +490,8 @@ pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Displa fn zero() -> Self; /// Returns new instance equalling one. fn one() -> Self; + /// Returns the largest value that can be represented by this integer type. + fn max_value() -> Self; /// Error type for converting from a decimal string. type FromDecStrErr; @@ -647,6 +649,15 @@ macro_rules! construct_uint { From::from(1u64) } + #[inline] + fn max_value() -> Self { + let mut result = [0; $n_words]; + for i in 0..$n_words { + result[i] = u64::max_value(); + } + $name(result) + } + /// Fast exponentation by squaring /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring fn pow(self, expon: Self) -> Self { From bc6a892f2b7987cfa7ee8e64cb684ec8720566fa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 22:12:52 +0100 Subject: [PATCH 718/753] Test outer create. --- ethcore/src/executive.rs | 56 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 40c69d97a..2421150e5 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -494,8 +494,8 @@ mod tests { assert_eq!(substate.contracts_created.len(), 0); } - evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int} - fn test_create_contract(factory: Factory) { + evm_test!{test_call_to_create: test_call_to_create_jit, test_call_to_create_int} + fn test_call_to_create(factory: Factory) { // code: // // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? @@ -571,6 +571,58 @@ mod tests { assert_eq!(gas_left, U256::from(44_752)); } + evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int} + fn test_create_contract(factory: Factory) { + // code: + // + // 60 10 - push 16 + // 80 - duplicate first stack item + // 60 0c - push 12 + // 60 00 - push 0 + // 39 - copy current code to memory + // 60 00 - push 0 + // f3 - return + + let code = "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(); + + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + let address = contract_address(&sender, &U256::zero()); + // TODO: add tests for 'callcreate' + //let next_address = contract_address(&address, &U256::zero()); + let mut params = ActionParams::default(); + params.address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(100_000); + params.code = Some(code.clone()); + params.value = ActionValue::Transfer(x!(100)); + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + state.add_balance(&sender, &U256::from(100)); + let info = EnvInfo::default(); + let engine = TestEngine::new(5, factory); + let mut substate = Substate::new(true); + + let gas_left = { + let mut ex = Executive::new(&mut state, &info, &engine); + ex.create(params.clone(), &mut substate).unwrap() + }; + + println!("trace: {:?}", substate.subtraces); + let expected_trace = Some(vec![Trace { + depth: 0, + action: TraceAction::Create(TraceCreate { + from: params.sender, + value: x!(100), + gas: params.gas, + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + result: Some((x!(3224), params.address, vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])), + }), + subs: vec![] + } ]); + assert_eq!(substate.subtraces, expected_trace); + assert_eq!(gas_left, U256::from(96_776)); + } evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int} fn test_create_contract_value_too_high(factory: Factory) { // code: From 7bba745f8b968e34186a4edee2aefece52f0e7b2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 22:14:16 +0100 Subject: [PATCH 719/753] Fix JSON test again. --- ethcore/src/json_tests/executive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 63638dfb3..dbb9bb6ab 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -239,7 +239,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { 0, OriginInfo::from(¶ms), &mut substate, - OutputPolicy::Return(&mut BytesRef::Flexible(&mut output), None), + OutputPolicy::Return(BytesRef::Flexible(&mut output), None), params.address.clone() ); let evm = engine.vm_factory().create(); From cabccf9ef59d7f83d74009be0dce8ee902de74a9 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sat, 19 Mar 2016 22:19:59 +0100 Subject: [PATCH 720/753] Test URL logged --- util/src/network/ip_utils.rs | 1 + util/src/network/tests.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs index b37a47064..27ff29737 100644 --- a/util/src/network/ip_utils.rs +++ b/util/src/network/ip_utils.rs @@ -208,6 +208,7 @@ fn can_select_public_address() { assert!(pub_address.port() == 40477); } +#[ignore] #[test] fn can_map_external_address_or_fail() { let pub_address = select_public_address(40478); diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index 0493475ce..8df3b4028 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -103,12 +103,14 @@ fn net_service() { #[test] fn net_connect() { + ::log::init_log(); let key1 = KeyPair::create().unwrap(); let mut config1 = NetworkConfiguration::new_local(); config1.use_secret = Some(key1.secret().clone()); config1.boot_nodes = vec![ ]; let mut service1 = NetworkService::::start(config1).unwrap(); let mut config2 = NetworkConfiguration::new_local(); + info!("net_connect: local URL: {}", service1.local_url()); config2.boot_nodes = vec![ service1.local_url() ]; let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1, false); From 2cb1937e1e4a50b420619276273195db24287a1a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 22:37:11 +0100 Subject: [PATCH 721/753] Move code to right module. --- ethcore/src/substate.rs | 25 ------------------------- ethcore/src/trace.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 9e6d0cea2..0610bffb8 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -65,31 +65,6 @@ impl Substate { } } -impl TraceAction { - /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a call. - pub fn from_call(p: &ActionParams) -> TraceAction { - TraceAction::Call(TraceCall { - from: p.sender.clone(), - to: p.address.clone(), - value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, - gas: p.gas.clone(), - input: p.data.clone().unwrap_or(vec![]), - result: None, - }) - } - - /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a create. - pub fn from_create(p: &ActionParams) -> TraceAction { - TraceAction::Create(TraceCreate { - from: p.sender.clone(), - value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, - gas: p.gas.clone(), - init: p.code.clone().unwrap_or(vec![]), - result: None, - }) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/ethcore/src/trace.rs b/ethcore/src/trace.rs index 1f45e846f..858230bcd 100644 --- a/ethcore/src/trace.rs +++ b/ethcore/src/trace.rs @@ -83,3 +83,29 @@ impl Default for Trace { } } } + +impl TraceAction { + /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a call. + pub fn from_call(p: &ActionParams) -> TraceAction { + TraceAction::Call(TraceCall { + from: p.sender.clone(), + to: p.address.clone(), + value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, + gas: p.gas.clone(), + input: p.data.clone().unwrap_or(vec![]), + result: None, + }) + } + + /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a create. + pub fn from_create(p: &ActionParams) -> TraceAction { + TraceAction::Create(TraceCreate { + from: p.sender.clone(), + value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, + gas: p.gas.clone(), + init: p.code.clone().unwrap_or(vec![]), + result: None, + }) + } +} + From b9623e6c5bbb60abbd6eed92453d0595e2ea106d Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 19 Mar 2016 23:27:50 +0100 Subject: [PATCH 722/753] improvements to build, updated dependencies, moved rpctest to its own submodule --- Cargo.lock | 131 ++++++++++--------- Cargo.toml | 6 - json/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- rpc/rpctest/Cargo.toml | 17 +++ parity/rpctest.rs => rpc/rpctest/src/main.rs | 0 6 files changed, 87 insertions(+), 71 deletions(-) create mode 100644 rpc/rpctest/Cargo.toml rename parity/rpctest.rs => rpc/rpctest/src/main.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index aa4f0a902..56bd823c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,6 @@ dependencies = [ "ethcore-devtools 1.1.0", "ethcore-rpc 1.1.0", "ethcore-util 1.1.0", - "ethjson 0.1.0", "ethminer 1.1.0", "ethsync 1.1.0", "fdlimit 0.1.0", @@ -20,7 +19,6 @@ dependencies = [ "rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -43,10 +41,10 @@ dependencies = [ [[package]] name = "aster" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -54,7 +52,7 @@ name = "bigint" version = "0.1.0" dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -141,7 +139,7 @@ source = "git+https://github.com/tomusdrw/rust-ctrlc.git#f4927770f89eca80ec25091 dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -165,7 +163,7 @@ name = "docopt" version = "0.6.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.58 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -181,7 +179,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -218,7 +216,7 @@ dependencies = [ "ethcore-devtools 1.1.0", "ethcore-util 1.1.0", "ethjson 0.1.0", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -244,14 +242,14 @@ dependencies = [ "ethcore-util 1.1.0", "ethminer 1.1.0", "ethsync 1.1.0", - "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -268,7 +266,7 @@ dependencies = [ "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", "ethcore-devtools 1.1.0", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", @@ -297,9 +295,9 @@ dependencies = [ "ethcore-util 1.1.0", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -325,7 +323,7 @@ dependencies = [ "ethcore 1.1.0", "ethcore-util 1.1.0", "ethminer 1.1.0", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -355,11 +353,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "heapsize" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -391,27 +388,27 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyper" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cookie 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -422,7 +419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.58 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -442,23 +439,23 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-http-server" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -466,7 +463,7 @@ name = "kernel32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -498,7 +495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librocksdb-sys" version = "0.2.3" -source = "git+https://github.com/arkpar/rust-rocksdb.git#ebb602fc74b4067f9f51310bdc0401b8e59b7156" +source = "git+https://github.com/arkpar/rust-rocksdb.git#ae44ef33ed1358ffc79aa05ed77839d555daba33" dependencies = [ "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -533,6 +530,14 @@ dependencies = [ "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mime" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mio" version = "0.5.0" @@ -542,11 +547,11 @@ dependencies = [ "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -555,20 +560,20 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "net2" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -667,20 +672,20 @@ dependencies = [ [[package]] name = "quasi" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quasi_codegen" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -703,7 +708,7 @@ dependencies = [ [[package]] name = "regex" -version = "0.1.56" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -720,7 +725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" version = "0.4.3" -source = "git+https://github.com/arkpar/rust-rocksdb.git#ebb602fc74b4067f9f51310bdc0401b8e59b7156" +source = "git+https://github.com/arkpar/rust-rocksdb.git#ae44ef33ed1358ffc79aa05ed77839d555daba33" dependencies = [ "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "librocksdb-sys 0.2.3 (git+https://github.com/arkpar/rust-rocksdb.git)", @@ -734,7 +739,7 @@ dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -790,14 +795,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_codegen" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -837,18 +842,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syntex" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syntex_syntax" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -867,7 +872,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -885,7 +890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -921,7 +926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicase" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -992,7 +997,7 @@ dependencies = [ [[package]] name = "winapi" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1005,7 +1010,7 @@ name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 62a3c31c7..e468799ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,8 +27,6 @@ ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } -ethjson = { path = "json" } -serde_json = "0.7.0" [features] default = ["rpc"] @@ -41,10 +39,6 @@ travis-nightly = ["ethcore/json-tests", "dev"] path = "parity/main.rs" name = "parity" -[[bin]] -path = "parity/rpctest.rs" -name = "rpctest" - [profile.release] debug = false lto = false diff --git a/json/Cargo.toml b/json/Cargo.toml index 91f8b8431..7887f2cea 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -14,7 +14,7 @@ clippy = { version = "0.0.54", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } -syntex = "0.29.0" +syntex = "0.30.0" [features] default = ["serde_codegen"] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index ca8004728..c28f598fd 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -26,7 +26,7 @@ clippy = { version = "0.0.54", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } -syntex = "0.29.0" +syntex = "0.30.0" [features] default = ["serde_codegen"] diff --git a/rpc/rpctest/Cargo.toml b/rpc/rpctest/Cargo.toml new file mode 100644 index 000000000..5b8f7f845 --- /dev/null +++ b/rpc/rpctest/Cargo.toml @@ -0,0 +1,17 @@ +[package] +description = "Rpc test client." +name = "rpctest" +version = "1.1.0" +license = "GPL-3.0" +authors = ["Ethcore "] + +[dependencies] +ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } +docopt = "0.6" +rustc-serialize = "0.3" +ethcore = { path = "../../ethcore" } +ethcore-devtools = { path = "../../devtools" } +ethcore-rpc = { path = ".." } +ethcore-util = { path = "../../util" } +ethjson = { path = "../../json" } +serde_json = "0.7.0" diff --git a/parity/rpctest.rs b/rpc/rpctest/src/main.rs similarity index 100% rename from parity/rpctest.rs rename to rpc/rpctest/src/main.rs From 387d0743e6b3a4a408ddd9331dafb779f2b72b00 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 19 Mar 2016 23:51:24 +0100 Subject: [PATCH 723/753] Allow 0x prefix for --author. --- parity/main.rs | 4 ++-- util/src/hash.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index c7e534993..56e70cf2a 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -46,6 +46,7 @@ use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; use util::panics::{MayPanic, ForwardPanic, PanicHandler}; +use util::keys::store::*; use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; @@ -55,7 +56,6 @@ use ethminer::{Miner, MinerService}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; -use util::keys::store::*; fn die_with_message(msg: &str) -> ! { println!("ERROR: {}", msg); @@ -315,7 +315,7 @@ impl Configuration { fn author(&self) -> Address { let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author); - Address::from_str(d).unwrap_or_else(|_| { + Address::from_str(clean_0x(d)).unwrap_or_else(|_| { die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", d) }) } diff --git a/util/src/hash.rs b/util/src/hash.rs index fce0720d1..b7fddbe8b 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -63,7 +63,8 @@ pub trait FixedHash: Sized + BytesConvertable + Populatable + FromStr + Default fn low_u64(&self) -> u64; } -fn clean_0x(s: &str) -> &str { +/// Return `s` without the `0x` at the beginning of it, if any. +pub fn clean_0x(s: &str) -> &str { if s.len() >= 2 && &s[0..2] == "0x" { &s[2..] } else { From fef8237701406bcdaee0fafe5d280fb15e2ecf5d Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 20 Mar 2016 10:07:50 +0100 Subject: [PATCH 724/753] fixes after merge --- ethcore/src/client/client.rs | 2 +- ethcore/src/client/test_client.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index bdc829159..1d34bf158 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -407,7 +407,7 @@ impl BlockChainClient for Client where V: Verifier { // give the sender max balance state.sub_balance(&sender, &balance); state.add_balance(&sender, &U256::max_value()); - Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t) + Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, false) } // TODO [todr] Should be moved to miner crate eventually. diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 5d51368de..db4be61bc 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -184,7 +184,7 @@ impl TestBlockChainClient { } impl BlockChainClient for TestBlockChainClient { - fn call(&self, t: &SignedTransaction) -> Result { + fn call(&self, _t: &SignedTransaction) -> Result { unimplemented!() } From c611566a3e45440cfdf9af028f9ef4433309ad0b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 10:19:21 +0100 Subject: [PATCH 725/753] Listen on all interfaces for JSONRPC by default. --- parity/main.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 56e70cf2a..39f5dcc82 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -105,8 +105,9 @@ Networking Options: API and Console Options: -j --jsonrpc Enable the JSON-RPC API sever. - --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API - server [default: 127.0.0.1]. + --jsonrpc-interface IP Specify the hostname portion of the JSONRPC API + server, IP should be an interface's IP address, or + all (all interfaces) or local [default: all]. --jsonrpc-port PORT Specify the port portion of the JSONRPC API server [default: 8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses @@ -149,7 +150,7 @@ Geth-compatibility Options: --nodekey KEY Equivalent to --node-key KEY. --nodiscover Equivalent to --no-discovery. --rpc Equivalent to --jsonrpc. - --rpcaddr HOST Equivalent to --jsonrpc-addr HOST. + --rpcaddr IP Equivalent to --jsonrpc-interface IP. --rpcport PORT Equivalent to --jsonrpc-port PORT. --rpcapi APIS Equivalent to --jsonrpc-apis APIS. --rpccorsdomain URL Equivalent to --jsonrpc-cors URL. @@ -188,7 +189,7 @@ struct Args { flag_cache_max_size: usize, flag_queue_max_size: usize, flag_jsonrpc: bool, - flag_jsonrpc_addr: String, + flag_jsonrpc_interface: String, flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, @@ -523,7 +524,11 @@ impl Configuration { // Setup rpc if self.args.flag_jsonrpc || self.args.flag_rpc { let url = format!("{}:{}", - self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_addr), + match self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_interface).as_str() { + "all" => "0.0.0.0", + "local" => "127.0.0.1", + x => x, + }, self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) ); SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); From 7c6f0e472d8feaa3642e886cb3bbea8e340171d9 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 20 Mar 2016 10:29:21 +0100 Subject: [PATCH 726/753] implementation of eth_estimateGas --- rpc/src/v1/impls/eth.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 3daa6275c..c66f04355 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -418,6 +418,26 @@ impl Eth for EthClient } }) } + + fn estimate_gas(&self, params: Params) -> Result { + from_params::<(TransactionRequest, BlockNumber)>(params) + .and_then(|(transaction_request, _block_number)| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&transaction_request.from) { + Ok(secret) => { + let client = take_weak!(self.client); + + let transaction: EthTransaction = transaction_request.into(); + let signed_transaction = transaction.sign(&secret); + + to_value(&client.call(&signed_transaction) + .map(|e| e.gas_used) + .unwrap_or(U256::zero())) + }, + Err(_) => { to_value(&U256::zero()) } + } + }) + } } /// Eth filter rpc implementation. From 05a9c163298a94b00cbd4c45e3bb7f27b02a651f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 10:34:34 +0100 Subject: [PATCH 727/753] JSONRPC interface defaults to local. Please enter the commit message for your changes. Lines starting --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 39f5dcc82..e029124c4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -107,7 +107,7 @@ API and Console Options: -j --jsonrpc Enable the JSON-RPC API sever. --jsonrpc-interface IP Specify the hostname portion of the JSONRPC API server, IP should be an interface's IP address, or - all (all interfaces) or local [default: all]. + all (all interfaces) or local [default: local]. --jsonrpc-port PORT Specify the port portion of the JSONRPC API server [default: 8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses From d536d206430df58a46fa9b41079a6884151261d9 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 20 Mar 2016 10:36:44 +0100 Subject: [PATCH 728/753] fixed indentation --- rpc/src/v1/impls/eth.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 3daa6275c..34a0c2f45 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -410,9 +410,11 @@ impl Eth for EthClient let transaction: EthTransaction = transaction_request.into(); let signed_transaction = transaction.sign(&secret); - to_value(&client.call(&signed_transaction) - .map(|e| Bytes::new(e.output)) - .unwrap_or(Bytes::default())) + let output = client.call(&signed_transaction) + .map(|e| Bytes::new(e.output)) + .unwrap_or(Bytes::default()); + + to_value(&output) }, Err(_) => { to_value(&Bytes::default()) } } From f75fb6a59faae7f6d7665153de4d4fbcdc2c8ccf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 11:33:36 +0100 Subject: [PATCH 729/753] Create transaction tracing test. --- ethcore/src/evm/factory.rs | 12 +++++------ ethcore/src/executive.rs | 2 ++ ethcore/src/state.rs | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/ethcore/src/evm/factory.rs b/ethcore/src/evm/factory.rs index 4a9bd38ba..65add0050 100644 --- a/ethcore/src/evm/factory.rs +++ b/ethcore/src/evm/factory.rs @@ -25,7 +25,7 @@ use evm::Evm; /// Type of EVM to use. pub enum VMType { /// JIT EVM - #[cfg(feature="jit")] + #[cfg(feature = "jit")] Jit, /// RUST EVM Interpreter @@ -52,13 +52,13 @@ impl fmt::Display for VMType { #[cfg(feature = "json-tests")] impl VMType { /// Return all possible VMs (JIT, Interpreter) - #[cfg(feature="jit")] + #[cfg(feature = "jit")] pub fn all() -> Vec { vec![VMType::Jit, VMType::Interpreter] } /// Return all possible VMs (Interpreter) - #[cfg(not(feature="jit"))] + #[cfg(not(feature = "jit"))] pub fn all() -> Vec { vec![VMType::Interpreter] } @@ -66,12 +66,12 @@ impl VMType { /// Evm factory. Creates appropriate Evm. pub struct Factory { - evm : VMType + evm: VMType } impl Factory { /// Create fresh instance of VM - #[cfg(feature="jit")] + #[cfg(feature = "jit")] pub fn create(&self) -> Box { match self.evm { VMType::Jit => { @@ -84,7 +84,7 @@ impl Factory { } /// Create fresh instance of VM - #[cfg(not(feature="jit"))] + #[cfg(not(feature = "jit"))] pub fn create(&self) -> Box { match self.evm { VMType::Interpreter => { diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 2421150e5..49cea6f23 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -310,6 +310,8 @@ impl<'a> Executive<'a> { c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, output)); } } + + trace!(target: "executive", "trace_info={:?}", trace_info); self.enact_result(&res, substate, unconfirmed_substate, trace_info); res diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index cad29b678..2f64401d2 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -349,6 +349,48 @@ use util::rlp::*; use account::*; use tests::helpers::*; use devtools::*; +use evm::factory::*; +use env_info::*; +use transaction::*; +use util::log::init_log; +use trace::*; + +#[test] +fn should_apply_create_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Create, + value: x!(100), + data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), + }.sign(&"".sha3()); + + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Create(TraceCreate { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + value: x!(100), + gas: x!(77412), + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + result: Some((x!(3224), x!("8988167e088c87cd314df6d3c2b83da5acb93ace"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} #[test] fn code_from_database() { From aa47d944e165c196f6f3237ad3aad05a68110d32 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 20 Mar 2016 11:34:19 +0100 Subject: [PATCH 730/753] implemented rpc eth_estimateGas method, added tests for rpc eth_call and eth_estimateGas --- ethcore/src/client/mod.rs | 2 +- ethcore/src/client/test_client.rs | 10 ++- ethcore/src/executive.rs | 2 +- rpc/src/v1/impls/eth.rs | 8 ++- rpc/src/v1/tests/eth.rs | 74 +++++++++++++++++--- rpc/src/v1/tests/helpers/account_provider.rs | 4 +- rpc/src/v1/types/transaction_request.rs | 25 +++++++ 7 files changed, 107 insertions(+), 18 deletions(-) diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 4a3208eb8..9663ab62b 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -25,6 +25,7 @@ pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; pub use self::ids::{BlockId, TransactionId}; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; +pub use executive::Executed; use std::collections::HashSet; use util::bytes::Bytes; @@ -38,7 +39,6 @@ use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; use error::{ImportResult, Error}; -use executive::Executed; /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index db4be61bc..ad73234b3 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -50,6 +50,8 @@ pub struct TestBlockChainClient { pub storage: RwLock>, /// Code. pub code: RwLock>, + /// Execution result. + pub execution_result: RwLock>, } #[derive(Clone)] @@ -84,12 +86,18 @@ impl TestBlockChainClient { balances: RwLock::new(HashMap::new()), storage: RwLock::new(HashMap::new()), code: RwLock::new(HashMap::new()), + execution_result: RwLock::new(None), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } + /// Set the execution result. + pub fn set_execution_result(&self, result: Executed) { + *self.execution_result.write().unwrap() = Some(result); + } + /// Set the balance of account `address` to `balance`. pub fn set_balance(&self, address: Address, balance: U256) { self.balances.write().unwrap().insert(address, balance); @@ -185,7 +193,7 @@ impl TestBlockChainClient { impl BlockChainClient for TestBlockChainClient { fn call(&self, _t: &SignedTransaction) -> Result { - unimplemented!() + Ok(self.execution_result.read().unwrap().clone().unwrap()) } fn block_total_difficulty(&self, _id: BlockId) -> Option { diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index d02f58815..1fbef7345 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -37,7 +37,7 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address { } /// Transaction execution receipt. -#[derive(Debug)] +#[derive(Debug, PartialEq, Clone)] pub struct Executed { /// Gas paid up front for execution of transaction. pub gas: U256, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 01625e9f9..a99a912f8 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -432,9 +432,11 @@ impl Eth for EthClient let transaction: EthTransaction = transaction_request.into(); let signed_transaction = transaction.sign(&secret); - to_value(&client.call(&signed_transaction) - .map(|e| e.gas_used) - .unwrap_or(U256::zero())) + let gas_used = client.call(&signed_transaction) + .map(|e| e.gas_used + e.refunded) + .unwrap_or(U256::zero()); + + to_value(&gas_used) }, Err(_) => { to_value(&U256::zero()) } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index a5f318350..72235b390 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -18,8 +18,8 @@ use std::collections::HashMap; use std::sync::{Arc, RwLock}; use jsonrpc_core::IoHandler; use util::hash::{Address, H256}; -use util::numbers::U256; -use ethcore::client::{TestBlockChainClient, EachBlockWith}; +use util::numbers::{Uint, U256}; +use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed}; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; @@ -299,9 +299,69 @@ fn rpc_eth_code() { } #[test] -#[ignore] fn rpc_eth_call() { - unimplemented!() + let tester = EthTester::default(); + tester.client.set_execution_result(Executed { + gas: U256::zero(), + gas_used: U256::from(0xff30), + refunded: U256::from(0x5), + cumulative_gas_used: U256::zero(), + logs: vec![], + contracts_created: vec![], + output: vec![0x12, 0x34, 0xff], + trace: None, + }); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_call", + "params": [{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }, + "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x1234ff","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_estimate_gas() { + let tester = EthTester::default(); + tester.client.set_execution_result(Executed { + gas: U256::zero(), + gas_used: U256::from(0xff30), + refunded: U256::from(0x5), + cumulative_gas_used: U256::zero(), + logs: vec![], + contracts_created: vec![], + output: vec![0x12, 0x34, 0xff], + trace: None, + }); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_estimateGas", + "params": [{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }, + "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0xff35","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } #[test] @@ -322,12 +382,6 @@ fn rpc_eth_sign() { unimplemented!() } -#[test] -#[ignore] -fn rpc_eth_estimate_gas() { - unimplemented!() -} - #[test] fn rpc_eth_compilers() { let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#; diff --git a/rpc/src/v1/tests/helpers/account_provider.rs b/rpc/src/v1/tests/helpers/account_provider.rs index 614aba346..6ef6e2b59 100644 --- a/rpc/src/v1/tests/helpers/account_provider.rs +++ b/rpc/src/v1/tests/helpers/account_provider.rs @@ -19,7 +19,7 @@ use std::sync::RwLock; use std::collections::HashMap; use std::io; -use util::hash::{Address, H256}; +use util::hash::{Address, H256, FixedHash}; use util::crypto::{Secret, Signature}; use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError}; @@ -83,7 +83,7 @@ impl AccountProvider for TestAccountProvider { } fn account_secret(&self, _account: &Address) -> Result { - unimplemented!() + Ok(Secret::random()) } fn sign(&self, _account: &Address, _message: &H256) -> Result { diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index d40402ab5..ed4dc19a2 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -46,6 +46,8 @@ impl Into for TransactionRequest { #[cfg(test)] mod tests { + use std::str::FromStr; + use rustc_serialize::hex::FromHex; use serde_json; use util::numbers::{Uint, U256}; use util::hash::Address; @@ -121,6 +123,29 @@ mod tests { }); } + #[test] + fn transaction_request_deserialize2() { + let s = r#"{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }"#; + let deserialized: TransactionRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, TransactionRequest { + from: Address::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap(), + to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + gas_price: Some(U256::from_str("9184e72a000").unwrap()), + gas: Some(U256::from_str("76c0").unwrap()), + value: Some(U256::from_str("9184e72a").unwrap()), + data: Some(Bytes::new("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap())), + nonce: None + }); + } + #[test] fn transaction_request_deserialize_empty() { let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#; From d2d5806e9b8df01aad9336da950cb6f4102b6b4a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 12:04:31 +0100 Subject: [PATCH 731/753] Test for failed create transactions, failed actions are logged as such. --- ethcore/src/executive.rs | 13 +++++++------ ethcore/src/state.rs | 38 ++++++++++++++++++++++++++++++++++++++ ethcore/src/substate.rs | 24 ++++++++++++++++-------- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 49cea6f23..7ae43ff0a 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -306,11 +306,9 @@ impl<'a> Executive<'a> { }; if let Some((TraceAction::Create(ref mut c), _)) = trace_info { - if let Some(output) = trace_output { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, output)); - } + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, trace_output.expect("trace_info is Some: qed"))); } - + trace!(target: "executive", "trace_info={:?}", trace_info); self.enact_result(&res, substate, unconfirmed_substate, trace_info); @@ -349,6 +347,8 @@ impl<'a> Executive<'a> { self.state.kill_account(address); } + let trace = substate.subtraces.and_then(|mut v| v.pop()); + match result { Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(_) => { @@ -359,7 +359,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + t.gas, logs: vec![], contracts_created: vec![], - trace: None, + trace: trace, }) }, _ => { @@ -370,7 +370,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, contracts_created: substate.contracts_created, - trace: substate.subtraces.and_then(|mut v| v.pop()), + trace: trace, }) }, } @@ -384,6 +384,7 @@ impl<'a> Executive<'a> { | Err(evm::Error::StackUnderflow {..}) | Err(evm::Error::OutOfStack {..}) => { self.state.revert_snapshot(); + substate.accrue_trace(un_substate.subtraces, maybe_info) }, Ok(_) | Err(evm::Error::Internal) => { self.state.clear_snapshot(); diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 2f64401d2..ef64ebbbe 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -392,6 +392,44 @@ fn should_apply_create_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_trace_failed_create_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Create, + value: x!(100), + data: FromHex::from_hex("5b600056").unwrap(), + }.sign(&"".sha3()); + + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Create(TraceCreate { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + value: x!(100), + gas: x!(78792), + init: FromHex::from_hex("5b600056").unwrap(), + result: None + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + + #[test] fn code_from_database() { let a = Address::zero(); diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 0610bffb8..9d81badb9 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -49,19 +49,27 @@ impl Substate { } } - /// Merge secondary substate `s` into self, accruing each element correspondingly. + /// Merge tracing information from substate `s` if enabled. + pub fn accrue_trace(&mut self, subs: Option>, maybe_info: Option<(TraceAction, usize)>) { + // it failed, so we don't bother accrueing any protocol-level stuff, only the + // trace info. + if let Some(info) = maybe_info { + self.subtraces.as_mut().expect("maybe_action is Some: so we must be tracing: qed").push(Trace { + action: info.0, + depth: info.1, + subs: subs.expect("maybe_action is Some: so we must be tracing: qed"), + }); + } + } + + /// Merge secondary substate `s` into self, accruing each element correspondingly; will merge + /// tracing information too, if enabled. pub fn accrue(&mut self, s: Substate, maybe_info: Option<(TraceAction, usize)>) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); - if let Some(info) = maybe_info { - self.subtraces.as_mut().expect("maybe_action is Some: so we must be tracing: qed").push(Trace { - action: info.0, - depth: info.1, - subs: s.subtraces.expect("maybe_action is Some: so we must be tracing: qed"), - }); - } + self.accrue_trace(s.subtraces, maybe_info); } } From 5afd32dd842e682c4aa0a37013d80f2116f70da8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 12:09:55 +0100 Subject: [PATCH 732/753] Minor tweaks. --- ethcore/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index ef64ebbbe..6135528c0 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -420,7 +420,7 @@ fn should_trace_failed_create_transaction() { from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), value: x!(100), gas: x!(78792), - init: FromHex::from_hex("5b600056").unwrap(), + init: vec![91, 96, 0, 86], result: None }), subs: vec![] From 2ec40604d923a4b0bd837bab51fd56b98c923a8a Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Sun, 20 Mar 2016 12:12:58 +0100 Subject: [PATCH 733/753] Revert "Auto detect available port" --- ethcore/src/service.rs | 2 +- util/src/network/host.rs | 93 ++++++++++++++++-------------------- util/src/network/ip_utils.rs | 1 - util/src/network/mod.rs | 2 +- util/src/network/service.rs | 21 ++------ util/src/network/session.rs | 2 +- util/src/network/tests.rs | 22 +++++---- 7 files changed, 60 insertions(+), 83 deletions(-) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 95a891198..bcfe7724f 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -146,7 +146,7 @@ mod tests { fn it_can_be_started() { let spec = get_test_spec(); let temp_path = RandomTempPath::new(); - let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path()); + let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path()); assert!(service.is_ok()); } } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 6baf0cf76..02c576424 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -105,14 +105,6 @@ impl NetworkConfiguration { config.listen_address = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap()); config } - - /// Create new default configuration for localhost-only connection with random port (usefull for testing) - pub fn new_local() -> NetworkConfiguration { - let mut config = NetworkConfiguration::new(); - config.listen_address = Some(SocketAddr::from_str("127.0.0.1:0").unwrap()); - config.nat_enabled = false; - config - } } // Tokens @@ -277,12 +269,12 @@ pub struct HostInfo { pub protocol_version: u32, /// Client identifier pub client_version: String, + /// TCP connection port. + pub listen_port: u16, /// Registered capabilities (handlers) pub capabilities: Vec, - /// Local address + discovery port - pub local_endpoint: NodeEndpoint, /// Public address + discovery port - pub public_endpoint: Option, + public_endpoint: NodeEndpoint, } impl HostInfo { @@ -315,7 +307,7 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, - tcp_listener: Mutex, + tcp_listener: Mutex>, handshakes: Arc>>, sessions: Arc>>, discovery: Mutex>, @@ -329,12 +321,13 @@ pub struct Host where Message: Send + Sync + Clone { impl Host where Message: Send + Sync + Clone { /// Create a new instance - pub fn new(config: NetworkConfiguration) -> Result, UtilError> { - let mut listen_address = match config.listen_address { + pub fn new(config: NetworkConfiguration) -> Host { + let listen_address = match config.listen_address { None => SocketAddr::from_str("0.0.0.0:30304").unwrap(), Some(addr) => addr, }; + let udp_port = config.udp_port.unwrap_or(listen_address.port()); let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { @@ -349,12 +342,7 @@ impl Host where Message: Send + Sync + Clone { |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; let path = config.config_path.clone(); - // Setup the server socket - let tcp_listener = try!(TcpListener::bind(&listen_address)); - listen_address = SocketAddr::new(listen_address.ip(), try!(tcp_listener.local_addr()).port()); - let udp_port = config.udp_port.unwrap_or(listen_address.port()); let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port }; - let mut host = Host:: { info: RwLock::new(HostInfo { keys: keys, @@ -362,12 +350,12 @@ impl Host where Message: Send + Sync + Clone { nonce: H256::random(), protocol_version: PROTOCOL_VERSION, client_version: version(), + listen_port: 0, capabilities: Vec::new(), - public_endpoint: None, - local_endpoint: local_endpoint, + public_endpoint: local_endpoint, // will be replaced by public once it is resolved }), discovery: Mutex::new(None), - tcp_listener: Mutex::new(tcp_listener), + tcp_listener: Mutex::new(None), handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), @@ -377,12 +365,14 @@ impl Host where Message: Send + Sync + Clone { stats: Arc::new(NetworkStats::default()), pinned_nodes: Vec::new(), }; + let port = listen_address.port(); + host.info.write().unwrap().deref_mut().listen_port = port; let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); for n in boot_nodes { host.add_node(&n); } - Ok(host) + host } pub fn stats(&self) -> Arc { @@ -407,50 +397,50 @@ impl Host where Message: Send + Sync + Clone { self.info.read().unwrap().client_version.clone() } - pub fn external_url(&self) -> Option { - self.info.read().unwrap().public_endpoint.as_ref().map(|e| format!("{}", Node::new(self.info.read().unwrap().id().clone(), e.clone()))) + pub fn client_url(&self) -> String { + format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().public_endpoint.clone())) } - pub fn local_url(&self) -> String { - let r = format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().local_endpoint.clone())); - println!("{}", r); - r - } - - fn init_public_interface(&self, io: &IoContext>) -> Result<(), UtilError> { + fn init_public_interface(&self, io: &IoContext>) { io.clear_timer(INIT_PUBLIC).unwrap(); - if self.info.read().unwrap().public_endpoint.is_some() { - return Ok(()); + let mut tcp_listener = self.tcp_listener.lock().unwrap(); + if tcp_listener.is_some() { + return; } - let local_endpoint = self.info.read().unwrap().local_endpoint.clone(); + // public_endpoint in host info contains local adderss at this point + let listen_address = self.info.read().unwrap().public_endpoint.address.clone(); + let udp_port = self.info.read().unwrap().config.udp_port.unwrap_or(listen_address.port()); let public_address = self.info.read().unwrap().config.public_address.clone(); let public_endpoint = match public_address { None => { - let public_address = select_public_address(local_endpoint.address.port()); - let public_endpoint = NodeEndpoint { address: public_address, udp_port: local_endpoint.udp_port }; + let public_address = select_public_address(listen_address.port()); + let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; if self.info.read().unwrap().config.nat_enabled { match map_external_address(&local_endpoint) { Some(endpoint) => { - info!("NAT mapped to external address {}", endpoint.address); + info!("NAT mappped to external address {}", endpoint.address); endpoint }, - None => public_endpoint + None => local_endpoint } } else { - public_endpoint + local_endpoint } } - Some(addr) => NodeEndpoint { address: addr, udp_port: local_endpoint.udp_port } + Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port } }; - self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone()); - info!("Public node URL: {}", self.external_url().unwrap()); + // Setup the server socket + *tcp_listener = Some(TcpListener::bind(&listen_address).unwrap()); + self.info.write().unwrap().public_endpoint = public_endpoint.clone(); + io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); + info!("Public node URL: {}", self.client_url()); // Initialize discovery. let discovery = { let info = self.info.read().unwrap(); if info.config.discovery_enabled && !info.config.pin { - Some(Discovery::new(&info.keys, public_endpoint.address.clone(), public_endpoint, DISCOVERY)) + Some(Discovery::new(&info.keys, listen_address.clone(), public_endpoint, DISCOVERY)) } else { None } }; @@ -464,8 +454,6 @@ impl Host where Message: Send + Sync + Clone { io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); *self.discovery.lock().unwrap().deref_mut() = Some(discovery); } - try!(io.register_stream(TCP_ACCEPT)); - Ok(()) } fn maintain_network(&self, io: &IoContext>) { @@ -579,7 +567,7 @@ impl Host where Message: Send + Sync + Clone { fn accept(&self, io: &IoContext>) { trace!(target: "network", "Accepting incoming connection"); loop { - let socket = match self.tcp_listener.lock().unwrap().accept() { + let socket = match self.tcp_listener.lock().unwrap().as_ref().unwrap().accept() { Ok(None) => break, Ok(Some((sock, _addr))) => sock, Err(e) => { @@ -873,8 +861,7 @@ impl IoHandler> for Host where Messa fn timeout(&self, io: &IoContext>, token: TimerToken) { match token { IDLE => self.maintain_network(io), - INIT_PUBLIC => self.init_public_interface(io).unwrap_or_else(|e| - warn!("Error initializing public interface: {:?}", e)), + INIT_PUBLIC => self.init_public_interface(io), FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { @@ -958,7 +945,7 @@ impl IoHandler> for Host where Messa } } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), - TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), + TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } } @@ -999,7 +986,7 @@ impl IoHandler> for Host where Messa } } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), - TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), + TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } } @@ -1067,6 +1054,6 @@ fn host_client_url() { let mut config = NetworkConfiguration::new(); let key = h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2"); config.use_secret = Some(key); - let host: Host = Host::new(config).unwrap(); - assert!(host.local_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); + let host: Host = Host::new(config); + assert!(host.client_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); } diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs index 27ff29737..b37a47064 100644 --- a/util/src/network/ip_utils.rs +++ b/util/src/network/ip_utils.rs @@ -208,7 +208,6 @@ fn can_select_public_address() { assert!(pub_address.port() == 40477); } -#[ignore] #[test] fn can_map_external_address_or_fail() { let pub_address = select_public_address(40478); diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index 29f3d166c..50645f2be 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -56,7 +56,7 @@ //! } //! //! fn main () { -//! let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); +//! let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40412)).expect("Error creating network service"); //! service.register_protocol(Arc::new(MyHandler), "myproto", &[1u8]); //! //! // Wait for quit condition diff --git a/util/src/network/service.rs b/util/src/network/service.rs index 49957f7e7..7b9388e85 100644 --- a/util/src/network/service.rs +++ b/util/src/network/service.rs @@ -28,7 +28,6 @@ use io::*; pub struct NetworkService where Message: Send + Sync + Clone + 'static { io_service: IoService>, host_info: String, - host: Arc>, stats: Arc, panic_handler: Arc } @@ -40,16 +39,15 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat let mut io_service = try!(IoService::>::start()); panic_handler.forward_from(&io_service); - let host = Arc::new(try!(Host::new(config))); + let host = Arc::new(Host::new(config)); let stats = host.stats().clone(); let host_info = host.client_version(); - try!(io_service.register_handler(host.clone())); + try!(io_service.register_handler(host)); Ok(NetworkService { io_service: io_service, host_info: host_info, stats: stats, - panic_handler: panic_handler, - host: host, + panic_handler: panic_handler }) } @@ -73,22 +71,13 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat &mut self.io_service } - /// Returns network statistics. + /// Returns underlying io service. pub fn stats(&self) -> &NetworkStats { &self.stats } - - /// Returns external url if available. - pub fn external_url(&self) -> Option { - self.host.external_url() - } - - /// Returns external url if available. - pub fn local_url(&self) -> String { - self.host.local_url() - } } + impl MayPanic for NetworkService where Message: Send + Sync + Clone + 'static { fn on_panic(&self, closure: F) where F: OnPanicListener { self.panic_handler.on_panic(closure); diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 7dbcc4229..2f30d7376 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -315,7 +315,7 @@ impl Session { .append(&host.protocol_version) .append(&host.client_version) .append(&host.capabilities) - .append(&host.local_endpoint.address.port()) + .append(&host.listen_port) .append(host.id()); self.connection.send_packet(&rlp.out()) } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index 8df3b4028..f8ef588f6 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -97,21 +97,21 @@ impl NetworkProtocolHandler for TestProtocol { #[test] fn net_service() { - let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); + let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40414)).expect("Error creating network service"); service.register_protocol(Arc::new(TestProtocol::new(false)), "myproto", &[1u8]).unwrap(); } #[test] fn net_connect() { - ::log::init_log(); let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_local(); + let mut config1 = NetworkConfiguration::new_with_port(30354); config1.use_secret = Some(key1.secret().clone()); + config1.nat_enabled = false; config1.boot_nodes = vec![ ]; + let mut config2 = NetworkConfiguration::new_with_port(30355); + config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30354", key1.public().hex()) ]; + config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); - let mut config2 = NetworkConfiguration::new_local(); - info!("net_connect: local URL: {}", service1.local_url()); - config2.boot_nodes = vec![ service1.local_url() ]; let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1, false); let handler2 = TestProtocol::register(&mut service2, false); @@ -125,12 +125,14 @@ fn net_connect() { #[test] fn net_disconnect() { let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_local(); + let mut config1 = NetworkConfiguration::new_with_port(30364); config1.use_secret = Some(key1.secret().clone()); + config1.nat_enabled = false; config1.boot_nodes = vec![ ]; + let mut config2 = NetworkConfiguration::new_with_port(30365); + config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30364", key1.public().hex()) ]; + config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); - let mut config2 = NetworkConfiguration::new_local(); - config2.boot_nodes = vec![ service1.local_url() ]; let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1, false); let handler2 = TestProtocol::register(&mut service2, true); @@ -143,7 +145,7 @@ fn net_disconnect() { #[test] fn net_timeout() { - let config = NetworkConfiguration::new_local(); + let config = NetworkConfiguration::new_with_port(30346); let mut service = NetworkService::::start(config).unwrap(); let handler = TestProtocol::register(&mut service, false); while !handler.got_timeout() { From ef10c6f6377955bbc709755632f21f5cb0451124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 20 Mar 2016 12:18:41 +0100 Subject: [PATCH 734/753] Avoiding possible overflow when block number gets smaller. --- miner/src/miner.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 699848337..e1b314d57 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -161,8 +161,8 @@ impl MinerService for Miner { let should_disable_sealing = { let current_no = chain.chain_info().best_block_number; let last_request = self.sealing_block_last_request.lock().unwrap(); - - current_no - *last_request > SEALING_TIMEOUT_IN_BLOCKS + let is_greater = current_no > *last_request; + is_greater && current_no - *last_request > SEALING_TIMEOUT_IN_BLOCKS }; if should_disable_sealing { From 6e9ea76aabefb0c9d62c684a1bdd563a2a475413 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 20 Mar 2016 11:35:46 +0100 Subject: [PATCH 735/753] Auto detect available port --- .travis.yml | 1 + ethcore/src/service.rs | 2 +- util/src/network/host.rs | 95 ++++++++++++++++++++---------------- util/src/network/ip_utils.rs | 1 + util/src/network/mod.rs | 2 +- util/src/network/service.rs | 21 ++++++-- util/src/network/session.rs | 2 +- util/src/network/tests.rs | 26 +++++----- 8 files changed, 87 insertions(+), 63 deletions(-) diff --git a/.travis.yml b/.travis.yml index f7ac723e1..f66b38c51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,7 @@ env: - RUN_COVERAGE="false" - RUN_BUILD="false" - RUN_BENCHES="false" + - RUST_BACKTRACE="1" cache: apt: true directories: diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index bcfe7724f..95a891198 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -146,7 +146,7 @@ mod tests { fn it_can_be_started() { let spec = get_test_spec(); let temp_path = RandomTempPath::new(); - let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_with_port(40456), &temp_path.as_path()); + let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path()); assert!(service.is_ok()); } } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 02c576424..d4e6d13ef 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -105,6 +105,14 @@ impl NetworkConfiguration { config.listen_address = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap()); config } + + /// Create new default configuration for localhost-only connection with random port (usefull for testing) + pub fn new_local() -> NetworkConfiguration { + let mut config = NetworkConfiguration::new(); + config.listen_address = Some(SocketAddr::from_str("127.0.0.1:0").unwrap()); + config.nat_enabled = false; + config + } } // Tokens @@ -269,12 +277,12 @@ pub struct HostInfo { pub protocol_version: u32, /// Client identifier pub client_version: String, - /// TCP connection port. - pub listen_port: u16, /// Registered capabilities (handlers) pub capabilities: Vec, + /// Local address + discovery port + pub local_endpoint: NodeEndpoint, /// Public address + discovery port - public_endpoint: NodeEndpoint, + pub public_endpoint: Option, } impl HostInfo { @@ -307,7 +315,7 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, - tcp_listener: Mutex>, + tcp_listener: Mutex, handshakes: Arc>>, sessions: Arc>>, discovery: Mutex>, @@ -321,13 +329,12 @@ pub struct Host where Message: Send + Sync + Clone { impl Host where Message: Send + Sync + Clone { /// Create a new instance - pub fn new(config: NetworkConfiguration) -> Host { - let listen_address = match config.listen_address { + pub fn new(config: NetworkConfiguration) -> Result, UtilError> { + let mut listen_address = match config.listen_address { None => SocketAddr::from_str("0.0.0.0:30304").unwrap(), Some(addr) => addr, }; - let udp_port = config.udp_port.unwrap_or(listen_address.port()); let keys = if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { @@ -342,7 +349,12 @@ impl Host where Message: Send + Sync + Clone { |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; let path = config.config_path.clone(); + // Setup the server socket + let tcp_listener = try!(TcpListener::bind(&listen_address)); + listen_address = SocketAddr::new(listen_address.ip(), try!(tcp_listener.local_addr()).port()); + let udp_port = config.udp_port.unwrap_or(listen_address.port()); let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port }; + let mut host = Host:: { info: RwLock::new(HostInfo { keys: keys, @@ -350,12 +362,12 @@ impl Host where Message: Send + Sync + Clone { nonce: H256::random(), protocol_version: PROTOCOL_VERSION, client_version: version(), - listen_port: 0, capabilities: Vec::new(), - public_endpoint: local_endpoint, // will be replaced by public once it is resolved + public_endpoint: None, + local_endpoint: local_endpoint, }), discovery: Mutex::new(None), - tcp_listener: Mutex::new(None), + tcp_listener: Mutex::new(tcp_listener), handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), @@ -365,14 +377,12 @@ impl Host where Message: Send + Sync + Clone { stats: Arc::new(NetworkStats::default()), pinned_nodes: Vec::new(), }; - let port = listen_address.port(); - host.info.write().unwrap().deref_mut().listen_port = port; let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); for n in boot_nodes { host.add_node(&n); } - host + Ok(host) } pub fn stats(&self) -> Arc { @@ -397,50 +407,50 @@ impl Host where Message: Send + Sync + Clone { self.info.read().unwrap().client_version.clone() } - pub fn client_url(&self) -> String { - format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().public_endpoint.clone())) + pub fn external_url(&self) -> Option { + self.info.read().unwrap().public_endpoint.as_ref().map(|e| format!("{}", Node::new(self.info.read().unwrap().id().clone(), e.clone()))) } - fn init_public_interface(&self, io: &IoContext>) { + pub fn local_url(&self) -> String { + let r = format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().local_endpoint.clone())); + println!("{}", r); + r + } + + fn init_public_interface(&self, io: &IoContext>) -> Result<(), UtilError> { io.clear_timer(INIT_PUBLIC).unwrap(); - let mut tcp_listener = self.tcp_listener.lock().unwrap(); - if tcp_listener.is_some() { - return; + if self.info.read().unwrap().public_endpoint.is_some() { + return Ok(()); } - // public_endpoint in host info contains local adderss at this point - let listen_address = self.info.read().unwrap().public_endpoint.address.clone(); - let udp_port = self.info.read().unwrap().config.udp_port.unwrap_or(listen_address.port()); + let local_endpoint = self.info.read().unwrap().local_endpoint.clone(); let public_address = self.info.read().unwrap().config.public_address.clone(); let public_endpoint = match public_address { None => { - let public_address = select_public_address(listen_address.port()); - let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port }; + let public_address = select_public_address(local_endpoint.address.port()); + let public_endpoint = NodeEndpoint { address: public_address, udp_port: local_endpoint.udp_port }; if self.info.read().unwrap().config.nat_enabled { match map_external_address(&local_endpoint) { Some(endpoint) => { - info!("NAT mappped to external address {}", endpoint.address); + info!("NAT mapped to external address {}", endpoint.address); endpoint }, - None => local_endpoint + None => public_endpoint } } else { - local_endpoint + public_endpoint } } - Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port } + Some(addr) => NodeEndpoint { address: addr, udp_port: local_endpoint.udp_port } }; - // Setup the server socket - *tcp_listener = Some(TcpListener::bind(&listen_address).unwrap()); - self.info.write().unwrap().public_endpoint = public_endpoint.clone(); - io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); - info!("Public node URL: {}", self.client_url()); + self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone()); + info!("Public node URL: {}", self.external_url().unwrap()); // Initialize discovery. let discovery = { let info = self.info.read().unwrap(); if info.config.discovery_enabled && !info.config.pin { - Some(Discovery::new(&info.keys, listen_address.clone(), public_endpoint, DISCOVERY)) + Some(Discovery::new(&info.keys, public_endpoint.address.clone(), public_endpoint, DISCOVERY)) } else { None } }; @@ -449,11 +459,13 @@ impl Host where Message: Send + Sync + Clone { for n in self.nodes.read().unwrap().unordered_entries() { discovery.add_node(n.clone()); } + *self.discovery.lock().unwrap().deref_mut() = Some(discovery); io.register_stream(DISCOVERY).expect("Error registering UDP listener"); io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); - *self.discovery.lock().unwrap().deref_mut() = Some(discovery); } + try!(io.register_stream(TCP_ACCEPT)); + Ok(()) } fn maintain_network(&self, io: &IoContext>) { @@ -567,7 +579,7 @@ impl Host where Message: Send + Sync + Clone { fn accept(&self, io: &IoContext>) { trace!(target: "network", "Accepting incoming connection"); loop { - let socket = match self.tcp_listener.lock().unwrap().as_ref().unwrap().accept() { + let socket = match self.tcp_listener.lock().unwrap().accept() { Ok(None) => break, Ok(Some((sock, _addr))) => sock, Err(e) => { @@ -861,7 +873,8 @@ impl IoHandler> for Host where Messa fn timeout(&self, io: &IoContext>, token: TimerToken) { match token { IDLE => self.maintain_network(io), - INIT_PUBLIC => self.init_public_interface(io), + INIT_PUBLIC => self.init_public_interface(io).unwrap_or_else(|e| + warn!("Error initializing public interface: {:?}", e)), FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { @@ -945,7 +958,7 @@ impl IoHandler> for Host where Messa } } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), - TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), + TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } } @@ -986,7 +999,7 @@ impl IoHandler> for Host where Messa } } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), - TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().as_ref().unwrap(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), + TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } } @@ -1054,6 +1067,6 @@ fn host_client_url() { let mut config = NetworkConfiguration::new(); let key = h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2"); config.use_secret = Some(key); - let host: Host = Host::new(config); - assert!(host.client_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); + let host: Host = Host::new(config).unwrap(); + assert!(host.local_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); } diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs index b37a47064..27ff29737 100644 --- a/util/src/network/ip_utils.rs +++ b/util/src/network/ip_utils.rs @@ -208,6 +208,7 @@ fn can_select_public_address() { assert!(pub_address.port() == 40477); } +#[ignore] #[test] fn can_map_external_address_or_fail() { let pub_address = select_public_address(40478); diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index 50645f2be..29f3d166c 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -56,7 +56,7 @@ //! } //! //! fn main () { -//! let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40412)).expect("Error creating network service"); +//! let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); //! service.register_protocol(Arc::new(MyHandler), "myproto", &[1u8]); //! //! // Wait for quit condition diff --git a/util/src/network/service.rs b/util/src/network/service.rs index 7b9388e85..49957f7e7 100644 --- a/util/src/network/service.rs +++ b/util/src/network/service.rs @@ -28,6 +28,7 @@ use io::*; pub struct NetworkService where Message: Send + Sync + Clone + 'static { io_service: IoService>, host_info: String, + host: Arc>, stats: Arc, panic_handler: Arc } @@ -39,15 +40,16 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat let mut io_service = try!(IoService::>::start()); panic_handler.forward_from(&io_service); - let host = Arc::new(Host::new(config)); + let host = Arc::new(try!(Host::new(config))); let stats = host.stats().clone(); let host_info = host.client_version(); - try!(io_service.register_handler(host)); + try!(io_service.register_handler(host.clone())); Ok(NetworkService { io_service: io_service, host_info: host_info, stats: stats, - panic_handler: panic_handler + panic_handler: panic_handler, + host: host, }) } @@ -71,12 +73,21 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat &mut self.io_service } - /// Returns underlying io service. + /// Returns network statistics. pub fn stats(&self) -> &NetworkStats { &self.stats } -} + /// Returns external url if available. + pub fn external_url(&self) -> Option { + self.host.external_url() + } + + /// Returns external url if available. + pub fn local_url(&self) -> String { + self.host.local_url() + } +} impl MayPanic for NetworkService where Message: Send + Sync + Clone + 'static { fn on_panic(&self, closure: F) where F: OnPanicListener { diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 2f30d7376..7dbcc4229 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -315,7 +315,7 @@ impl Session { .append(&host.protocol_version) .append(&host.client_version) .append(&host.capabilities) - .append(&host.listen_port) + .append(&host.local_endpoint.address.port()) .append(host.id()); self.connection.send_packet(&rlp.out()) } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index f8ef588f6..b43da9320 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -97,23 +97,23 @@ impl NetworkProtocolHandler for TestProtocol { #[test] fn net_service() { - let mut service = NetworkService::::start(NetworkConfiguration::new_with_port(40414)).expect("Error creating network service"); + let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); service.register_protocol(Arc::new(TestProtocol::new(false)), "myproto", &[1u8]).unwrap(); } #[test] fn net_connect() { + ::log::init_log(); let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_with_port(30354); + let mut config1 = NetworkConfiguration::new_local(); config1.use_secret = Some(key1.secret().clone()); - config1.nat_enabled = false; config1.boot_nodes = vec![ ]; - let mut config2 = NetworkConfiguration::new_with_port(30355); - config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30354", key1.public().hex()) ]; - config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); - let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1, false); + let mut config2 = NetworkConfiguration::new_local(); + info!("net_connect: local URL: {}", service1.local_url()); + config2.boot_nodes = vec![ service1.local_url() ]; + let mut service2 = NetworkService::::start(config2).unwrap(); let handler2 = TestProtocol::register(&mut service2, false); while !handler1.got_packet() && !handler2.got_packet() && (service1.stats().sessions() == 0 || service2.stats().sessions() == 0) { thread::sleep(Duration::from_millis(50)); @@ -125,16 +125,14 @@ fn net_connect() { #[test] fn net_disconnect() { let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_with_port(30364); + let mut config1 = NetworkConfiguration::new_local(); config1.use_secret = Some(key1.secret().clone()); - config1.nat_enabled = false; config1.boot_nodes = vec![ ]; - let mut config2 = NetworkConfiguration::new_with_port(30365); - config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30364", key1.public().hex()) ]; - config2.nat_enabled = false; let mut service1 = NetworkService::::start(config1).unwrap(); - let mut service2 = NetworkService::::start(config2).unwrap(); let handler1 = TestProtocol::register(&mut service1, false); + let mut config2 = NetworkConfiguration::new_local(); + config2.boot_nodes = vec![ service1.local_url() ]; + let mut service2 = NetworkService::::start(config2).unwrap(); let handler2 = TestProtocol::register(&mut service2, true); while !(handler1.got_disconnect() && handler2.got_disconnect()) { thread::sleep(Duration::from_millis(50)); @@ -145,7 +143,7 @@ fn net_disconnect() { #[test] fn net_timeout() { - let config = NetworkConfiguration::new_with_port(30346); + let config = NetworkConfiguration::new_local(); let mut service = NetworkService::::start(config).unwrap(); let handler = TestProtocol::register(&mut service, false); while !handler.got_timeout() { From 6ac350a9960a5f701dc722402e84a1ba6cf8aeb2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 16:24:19 +0100 Subject: [PATCH 736/753] Tests for lots more configurations. --- ethcore/src/executive.rs | 10 +- ethcore/src/externalities.rs | 16 +- ethcore/src/state.rs | 307 +++++++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+), 13 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 7ae43ff0a..e4d0650d0 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -260,16 +260,14 @@ impl<'a> Executive<'a> { // if there's tracing, make up trace_info's result with trace_output and some arithmetic. if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - if let Some(output) = trace_output { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, output)); - } + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: qed"))); } - trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); - trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); + trace!(target: "executive", "sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); + trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); self.enact_result(&res, substate, unconfirmed_substate, trace_info); - trace!("exec: new substate={:?}\n", substate); + trace!(target: "executive", "enacted: substate={:?}\n", substate); res } else { // otherwise, nothing diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index a6f7e4f36..3f9d4ff08 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -153,13 +153,15 @@ impl<'a> Ext for Externalities<'a> { } fn call(&mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, - value: Option, - data: &[u8], - code_address: &Address, - output: &mut [u8]) -> MessageCallResult { + gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option, + data: &[u8], + code_address: &Address, + output: &mut [u8] + ) -> MessageCallResult { + trace!(target: "externalities", "call"); let mut params = ActionParams { sender: sender_address.clone(), diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 6135528c0..b5b312076 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -429,6 +429,313 @@ fn should_trace_failed_create_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_trace_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + + +#[test] +fn should_trace_failed_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: None + }), + subs: vec![] + }); + + println!("trace: {:?}", result.trace); + + assert_eq!(result.trace, expected_trace); +} +#[test] +fn should_trace_call_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(69), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(79000), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: None + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_call_with_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); + state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(135), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: Some((x!(69), vec![])) + }), + subs: vec![Trace { + depth: 2, + action: TraceAction::Call(TraceCall { + from: x!(0xb), + to: x!(0xc), + value: x!(0), + gas: x!(78868), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); + state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(79000), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: None + }), + subs: vec![Trace { + depth: 2, + action: TraceAction::Call(TraceCall { + from: x!(0xb), + to: x!(0xc), + value: x!(0), + gas: x!(78868), + input: vec![], + result: Some((x!(3), vec![])), + }), + subs: vec![] + }] + }] + }); + + assert_eq!(result.trace, expected_trace); +} #[test] fn code_from_database() { From 2a3e695f8a9ee043966af0a90fbbabf4f6ec8b01 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 20 Mar 2016 17:29:39 +0100 Subject: [PATCH 737/753] LocalizedReceipt --- ethcore/src/blockchain/blockchain.rs | 5 +++ ethcore/src/client/client.rs | 23 ++++++++---- ethcore/src/client/mod.rs | 4 ++ ethcore/src/client/test_client.rs | 4 ++ ethcore/src/receipt.rs | 23 +++++++++++- rpc/src/v1/impls/eth.rs | 6 +++ rpc/src/v1/types/mod.rs.in | 2 + rpc/src/v1/types/receipt.rs | 56 ++++++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 rpc/src/v1/types/receipt.rs diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7e1a8e23f..43920708b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -103,6 +103,11 @@ pub trait BlockProvider { self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)) } + /// Get transaction receipt. + fn transaction_receipt(&self, address: &TransactionAddress) -> Option { + self.block_receipts(&address.block_hash).and_then(|br| br.receipts.into_iter().nth(address.index)) + } + /// Get a list of transactions for a given block. /// Returns None if block does not exist. fn transactions(&self, hash: &H256) -> Option> { diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 1d34bf158..c8c9002d7 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -39,6 +39,7 @@ use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; use env_info::EnvInfo; use executive::{Executive, Executed}; +use receipt::Receipt; pub use blockchain::CacheSize as BlockChainCacheSize; /// General block status @@ -384,6 +385,16 @@ impl Client where V: Verifier { BlockId::Latest => Some(self.chain.best_block_number()) } } + + fn transaction_address(&self, id: TransactionId) -> Option { + match id { + TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), + TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress { + block_hash: hash, + index: index + }) + } + } } impl BlockChainClient for Client where V: Verifier { @@ -535,13 +546,11 @@ impl BlockChainClient for Client where V: Verifier { } fn transaction(&self, id: TransactionId) -> Option { - match id { - TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), - TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress { - block_hash: hash, - index: index - }) - }.and_then(|address| self.chain.transaction(&address)) + self.transaction_address(id).and_then(|address| self.chain.transaction(&address)) + } + + fn transaction_receipt(&self, id: TransactionId) -> Option { + self.transaction_address(id).and_then(|address| self.chain.transaction_receipt(&address)) } fn tree_route(&self, from: &H256, to: &H256) -> Option { diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 9663ab62b..420fcf75e 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -39,6 +39,7 @@ use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; use error::{ImportResult, Error}; +use receipt::Receipt; /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -76,6 +77,9 @@ pub trait BlockChainClient : Sync + Send { /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; + /// Get transaction receipt with given hash. + fn transaction_receipt(&self, id: TransactionId) -> Option; + /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. fn tree_route(&self, from: &H256, to: &H256) -> Option; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index ad73234b3..fbff834ba 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -224,6 +224,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn transaction_receipt(&self, _id: TransactionId) -> Option { + unimplemented!(); + } + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { unimplemented!(); } diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index ae83a174a..7f0b0d8dd 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -18,7 +18,8 @@ use util::*; use basic_types::LogBloom; -use log_entry::LogEntry; +use header::BlockNumber; +use log_entry::{LogEntry, LocalizedLogEntry}; /// Information describing execution of a transaction. #[derive(Default, Debug, Clone)] @@ -74,6 +75,26 @@ impl HeapSizeOf for Receipt { } } +/// Receipt with additional info. +pub struct LocalizedReceipt { + /// Transaction hash. + pub transaction_hash: H256, + /// Transaction index. + pub transaction_index: usize, + /// Block hash. + pub block_hash: H256, + /// Block number. + pub block_number: BlockNumber, + /// Cumulative gas used. + pub cumulative_gas_used: U256, + /// Gas used. + pub gas_used: U256, + /// Contract address. + pub contract_address: Option
, + /// Logs + pub logs: Vec, +} + #[test] fn test_basic() { let expected = FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a99a912f8..950cdb783 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -293,6 +293,12 @@ impl Eth for EthClient .and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value()))) } + fn transaction_receipt(&self, params: Params) -> Result { + unimplemented!(); + //from_params::<(H256,)>(params) + //.and_then(|(hash,)| self.transaction_receipt(TransactionId::Hash(hash))) + } + fn uncle_by_block_hash_and_index(&self, params: Params) -> Result { from_params::<(H256, Index)>(params) .and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value())) diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index ebc3bc0ff..0121e4aea 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -24,6 +24,7 @@ mod optionals; mod sync; mod transaction; mod transaction_request; +mod receipt; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; @@ -35,4 +36,5 @@ pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; pub use self::transaction_request::TransactionRequest; +pub use self::receipt::Receipt; diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs new file mode 100644 index 000000000..fa34d5df5 --- /dev/null +++ b/rpc/src/v1/types/receipt.rs @@ -0,0 +1,56 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::numbers::U256; +use util::hash::{Address, H256}; +use v1::types::Log; +use ethcore::receipt::LocalizedReceipt; + +#[derive(Debug, Serialize)] +pub struct Receipt { + #[serde(rename="transactionHash")] + pub transaction_hash: H256, + #[serde(rename="transactionIndex")] + pub transaction_index: U256, + #[serde(rename="blockHash")] + pub block_hash: H256, + #[serde(rename="blockNumber")] + pub block_number: U256, + #[serde(rename="cumulativeGasUsed")] + pub cumulative_gas_used: U256, + #[serde(rename="gasUsed")] + pub gas_used: U256, + #[serde(rename="contractAddress")] + pub contract_address: Option
, + pub logs: Vec, +} + +impl From for Receipt { + fn from(r: LocalizedReceipt) -> Self { + Receipt { + transaction_hash: r.transaction_hash, + transaction_index: U256::from(r.transaction_index), + block_hash: r.block_hash, + block_number: U256::from(r.block_number), + cumulative_gas_used: r.cumulative_gas_used, + gas_used: r.gas_used, + contract_address: r.contract_address, + logs: r.logs.into_iter().map(From::from).collect(), + } + } +} + + From c2933e005ab4d011452c81e77a98c130ac0de323 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 17:51:22 +0100 Subject: [PATCH 738/753] Tests for not tracking builtin calls. --- ethcore/src/state.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index b5b312076..78084e6db 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -351,6 +351,7 @@ use tests::helpers::*; use devtools::*; use evm::factory::*; use env_info::*; +use spec::*; use transaction::*; use util::log::init_log; use trace::*; @@ -468,6 +469,68 @@ fn should_trace_call_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_not_trace_call_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0x1)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + assert_eq!(result.trace, None); +} + +#[test] +fn should_not_trace_subcall_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(0), + gas: x!(79000), + input: vec![], + result: Some((x!(28061), vec![])) + }), + subs: vec![] + }); + assert_eq!(result.trace, expected_trace); +} #[test] fn should_trace_failed_call_transaction() { From 52e980172154c71f23082eb11acb78de8cdebaa9 Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 20 Mar 2016 18:44:57 +0100 Subject: [PATCH 739/753] client implementation of transaction receipt --- ethcore/src/client/client.rs | 40 +++++++++++++++++++++++++++---- ethcore/src/client/mod.rs | 4 ++-- ethcore/src/client/test_client.rs | 4 ++-- ethcore/src/log_entry.rs | 3 ++- rpc/src/v1/impls/eth.rs | 11 +++++---- 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c8c9002d7..b2254e285 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -39,7 +39,7 @@ use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; use env_info::EnvInfo; use executive::{Executive, Executed}; -use receipt::Receipt; +use receipt::LocalizedReceipt; pub use blockchain::CacheSize as BlockChainCacheSize; /// General block status @@ -549,8 +549,40 @@ impl BlockChainClient for Client where V: Verifier { self.transaction_address(id).and_then(|address| self.chain.transaction(&address)) } - fn transaction_receipt(&self, id: TransactionId) -> Option { - self.transaction_address(id).and_then(|address| self.chain.transaction_receipt(&address)) + fn transaction_receipt(&self, id: TransactionId) -> Option { + self.transaction_address(id).and_then(|address| { + let t = self.chain.block(&address.block_hash) + .and_then(|block| BlockView::new(&block).localized_transaction_at(address.index)); + + match (t, self.chain.transaction_receipt(&address)) { + (Some(tx), Some(receipt)) => { + let block_hash = tx.block_hash.clone(); + let block_number = tx.block_number.clone(); + let transaction_hash = tx.hash(); + let transaction_index = tx.transaction_index; + Some(LocalizedReceipt { + transaction_hash: tx.hash(), + transaction_index: tx.transaction_index, + block_hash: tx.block_hash, + block_number: tx.block_number, + // TODO: to fix this, query all previous transaction receipts and retrieve their gas usage + cumulative_gas_used: receipt.gas_used, + gas_used: receipt.gas_used, + // TODO: to fix this, store created contract address in db + contract_address: None, + logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry { + entry: log, + block_hash: block_hash.clone(), + block_number: block_number, + transaction_hash: transaction_hash.clone(), + transaction_index: transaction_index, + log_index: i + }).collect() + }) + }, + _ => None + } + }) } fn tree_route(&self, from: &H256, to: &H256) -> Option { @@ -635,7 +667,7 @@ impl BlockChainClient for Client where V: Verifier { .map(|(i, log)| LocalizedLogEntry { entry: log, block_hash: hash.clone(), - block_number: number as usize, + block_number: number, transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new), transaction_index: index, log_index: log_index + i diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 420fcf75e..74b05652f 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -39,7 +39,7 @@ use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; use error::{ImportResult, Error}; -use receipt::Receipt; +use receipt::LocalizedReceipt; /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -78,7 +78,7 @@ pub trait BlockChainClient : Sync + Send { fn transaction(&self, id: TransactionId) -> Option; /// Get transaction receipt with given hash. - fn transaction_receipt(&self, id: TransactionId) -> Option; + fn transaction_receipt(&self, id: TransactionId) -> Option; /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index fbff834ba..0adaae7e5 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -23,7 +23,7 @@ use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, Transaction use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; -use receipt::Receipt; +use receipt::{Receipt, LocalizedReceipt}; use extras::BlockReceipts; use error::{ImportResult}; @@ -224,7 +224,7 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn transaction_receipt(&self, _id: TransactionId) -> Option { + fn transaction_receipt(&self, _id: TransactionId) -> Option { unimplemented!(); } diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index 63d09b4f0..cf74a6df9 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -18,6 +18,7 @@ use util::*; use basic_types::LogBloom; +use header::BlockNumber; /// A record of execution for a `LOG` operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -84,7 +85,7 @@ pub struct LocalizedLogEntry { /// Block in which this log was created. pub block_hash: H256, /// Block number. - pub block_number: usize, + pub block_number: BlockNumber, /// Hash of transaction in which this log was created. pub transaction_hash: H256, /// Index of transaction within block. diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 950cdb783..d7ee478bf 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -31,7 +31,7 @@ use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use ethcore::transaction::Transaction as EthTransaction; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner}; use util::keys::store::AccountProvider; @@ -294,9 +294,12 @@ impl Eth for EthClient } fn transaction_receipt(&self, params: Params) -> Result { - unimplemented!(); - //from_params::<(H256,)>(params) - //.and_then(|(hash,)| self.transaction_receipt(TransactionId::Hash(hash))) + from_params::<(H256,)>(params) + .and_then(|(hash,)| { + let client = take_weak!(self.client); + let receipt = client.transaction_receipt(TransactionId::Hash(hash)); + to_value(&receipt.map(Receipt::from)) + }) } fn uncle_by_block_hash_and_index(&self, params: Params) -> Result { From 72b604b8e87145c96ace89918c6a54f0d63d44cc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 20 Mar 2016 19:20:37 +0100 Subject: [PATCH 740/753] Avoid tracing DELEGATECALL and CALLCODE. Plus tests for it. --- ethcore/res/null_homestead_morden.json | 35 +++++++++++ ethcore/res/null_morden.json | 2 +- ethcore/src/engine.rs | 10 ++++ ethcore/src/ethereum/ethash.rs | 20 +++---- ethcore/src/evm/interpreter.rs | 32 +++++----- ethcore/src/executive.rs | 11 +++- ethcore/src/null_engine.rs | 11 +++- ethcore/src/spec/spec.rs | 3 + ethcore/src/state.rs | 82 ++++++++++++++++++++++++++ 9 files changed, 177 insertions(+), 29 deletions(-) create mode 100644 ethcore/res/null_homestead_morden.json diff --git a/ethcore/res/null_homestead_morden.json b/ethcore/res/null_homestead_morden.json new file mode 100644 index 000000000..abd3f4de9 --- /dev/null +++ b/ethcore/res/null_homestead_morden.json @@ -0,0 +1,35 @@ +{ + "name": "Morden", + "engineName": "NullEngine", + "params": { + "accountStartNonce": "0x0100000", + "frontierCompatibilityModeLimit": "0x0", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar": "", + "networkID" : "0x2" + }, + "genesis": { + "nonce": "0x00006d6f7264656e", + "difficulty": "0x20000", + "mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x2fefd8" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } + } +} diff --git a/ethcore/res/null_morden.json b/ethcore/res/null_morden.json index 70b48fbdb..86148d640 100644 --- a/ethcore/res/null_morden.json +++ b/ethcore/res/null_morden.json @@ -3,7 +3,7 @@ "engineName": "NullEngine", "params": { "accountStartNonce": "0x0100000", - "frontierCompatibilityModeLimit": "0xfffa2990", + "frontierCompatibilityModeLimit": "0x789b0", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index 0b2ce8ae2..7698af529 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -103,4 +103,14 @@ pub trait Engine : Sync + Send { fn execute_builtin(&self, a: &Address, input: &[u8], output: &mut [u8]) { self.spec().builtins.get(a).unwrap().execute(input, output); } // TODO: sealing stuff - though might want to leave this for later. + + /// Get a named parameter from the `spec()`'s `engine_params` item and convert to u64, or 0 if that fails. + fn u64_param(&self, name: &str) -> u64 { + self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a)) + } + + /// Get a named parameter from the `spec()`'s `engine_params` item and convert to U256, or 0 if that fails. + fn u256_param(&self, name: &str) -> U256 { + self.spec().engine_params.get(name).map_or(x!(0), |a| decode(&a)) + } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 6f854921d..d2c56ebf1 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -57,16 +57,6 @@ impl Ethash { u256_params: RwLock::new(HashMap::new()) } } - - fn u64_param(&self, name: &str) -> u64 { - *self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| - self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a))) - } - - fn u256_param(&self, name: &str) -> U256 { - *self.u256_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| - self.spec().engine_params.get(name).map_or(x!(0), |a| decode(&a))) - } } impl Engine for Ethash { @@ -199,6 +189,16 @@ impl Engine for Ethash { fn verify_transaction(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> { t.sender().map(|_|()) // Perform EC recovery and cache sender } + + fn u64_param(&self, name: &str) -> u64 { + *self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| + self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a))) + } + + fn u256_param(&self, name: &str) -> U256 { + *self.u256_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| + self.spec().engine_params.get(name).map_or(x!(0), |a| decode(&a))) + } } #[cfg_attr(feature="dev", allow(wrong_self_convention))] // to_ethash should take self diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index b29fc0d41..eb29ef257 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -348,12 +348,13 @@ impl evm::Evm for Interpreter { impl Interpreter { #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] - fn get_gas_cost_mem(&self, - ext: &evm::Ext, - instruction: Instruction, - mem: &mut Memory, - stack: &Stack - ) -> Result<(U256, usize), evm::Error> { + fn get_gas_cost_mem( + &self, + ext: &evm::Ext, + instruction: Instruction, + mem: &mut Memory, + stack: &Stack + ) -> Result<(U256, usize), evm::Error> { let schedule = ext.schedule(); let info = instructions::get_info(instruction); @@ -522,15 +523,16 @@ impl Interpreter { } #[cfg_attr(feature="dev", allow(too_many_arguments))] - fn exec_instruction(&self, - gas: Gas, - params: &ActionParams, - ext: &mut evm::Ext, - instruction: Instruction, - code: &mut CodeReader, - mem: &mut Memory, - stack: &mut Stack - ) -> Result { + fn exec_instruction( + &self, + gas: Gas, + params: &ActionParams, + ext: &mut evm::Ext, + instruction: Instruction, + code: &mut CodeReader, + mem: &mut Memory, + stack: &mut Stack + ) -> Result { match instruction { instructions::JUMP => { let jump = stack.pop_back(); diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 6ea39ec3b..c862545f4 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -196,6 +196,7 @@ impl<'a> Executive<'a> { if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 { let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy); let vm_factory = self.engine.vm_factory(); + trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); return vm_factory.create().exec(params, &mut ext); } @@ -247,24 +248,30 @@ impl<'a> Executive<'a> { } } else if params.code.is_some() { // if destination is a contract, do normal message call + + // don't trace is it's DELEGATECALL or CALLCODE. + let should_trace = if let ActionValue::Transfer(_) = params.value { + params.code_address == params.address + } else { false }; // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); // transaction tracing stuff. None if there's no tracing. - let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)); + let mut trace_info = if should_trace { substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)) } else { None }; let mut trace_output = trace_info.as_ref().map(|_| vec![]); let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) }; + trace!(target: "executive", "res={:?}", res); + // if there's tracing, make up trace_info's result with trace_output and some arithmetic. if let Some((TraceAction::Call(ref mut c), _)) = trace_info { c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: qed"))); } - trace!(target: "executive", "sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); self.enact_result(&res, substate, unconfirmed_substate, trace_info); diff --git a/ethcore/src/null_engine.rs b/ethcore/src/null_engine.rs index af7255617..99231add4 100644 --- a/ethcore/src/null_engine.rs +++ b/ethcore/src/null_engine.rs @@ -41,7 +41,16 @@ impl Engine for NullEngine { fn vm_factory(&self) -> &Factory { &self.factory } + fn name(&self) -> &str { "NullEngine" } + fn spec(&self) -> &Spec { &self.spec } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { Schedule::new_frontier() } + + fn schedule(&self, env_info: &EnvInfo) -> Schedule { + if env_info.number < self.u64_param("frontierCompatibilityModeLimit") { + Schedule::new_frontier() + } else { + Schedule::new_homestead() + } + } } diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index c7e2e4e9f..f97d8c8dc 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -333,6 +333,9 @@ impl Spec { /// Create a new Spec which conforms to the Morden chain except that it's a NullEngine consensus. pub fn new_test() -> Spec { Self::from_json_utf8(include_bytes!("../../res/null_morden.json")) } + + /// Create a new Spec which conforms to the Morden chain except that it's a NullEngine consensus. + pub fn new_homestead_test() -> Spec { Self::from_json_utf8(include_bytes!("../../res/null_homestead_morden.json")) } } #[cfg(test)] diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 78084e6db..c2924d1bb 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -532,6 +532,87 @@ fn should_not_trace_subcall_transaction_to_builtin() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_not_trace_callcode() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(0), + gas: x!(79000), + input: vec![], + result: Some((x!(64), vec![])) + }), + subs: vec![] + }); + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_not_trace_delegatecall() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + info.number = 0x789b0; + let engine = Spec::new_test().to_engine().unwrap(); + + println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(0), + gas: x!(79000), + input: vec![], + result: Some((x!(61), vec![])) + }), + subs: vec![] + }); + assert_eq!(result.trace, expected_trace); +} + #[test] fn should_trace_failed_call_transaction() { init_log(); @@ -572,6 +653,7 @@ fn should_trace_failed_call_transaction() { assert_eq!(result.trace, expected_trace); } + #[test] fn should_trace_call_with_subcall_transaction() { init_log(); From 677193ca52033335c2ffd5c234b19373b21db7b1 Mon Sep 17 00:00:00 2001 From: Alexander Orlov Date: Sun, 20 Mar 2016 20:44:32 +0100 Subject: [PATCH 741/753] complete getting started steps for OS X You get `multirust: no default toolchain configured` when `multirust default stable` is not executed. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 47a27e30e..7aa5e8858 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install. - OSX with Homebrew: ```bash brew update && brew install multirust +multirust default stable ``` Then, download and build Parity: From c4d45e0cf049fc8a92ba9888cbbc22678178d766 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 21 Mar 2016 11:24:03 +0100 Subject: [PATCH 742/753] Trace basic calls! And tests. --- ethcore/src/executive.rs | 60 ++++++++++-------- ethcore/src/state.rs | 127 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 25 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index c862545f4..8c34b8e39 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -246,41 +246,49 @@ impl<'a> Executive<'a> { Err(evm::Error::OutOfGas) } } - } else if params.code.is_some() { + } else { // if destination is a contract, do normal message call - // don't trace is it's DELEGATECALL or CALLCODE. + // don't trace if it's DELEGATECALL or CALLCODE. let should_trace = if let ActionValue::Transfer(_) = params.value { - params.code_address == params.address + params.code_address == params.address && substate.subtraces.is_some() } else { false }; - // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); - // transaction tracing stuff. None if there's no tracing. - let mut trace_info = if should_trace { substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)) } else { None }; - let mut trace_output = trace_info.as_ref().map(|_| vec![]); + let (mut trace_info, mut trace_output) = if should_trace { + (Some((TraceAction::from_call(¶ms), self.depth)), Some(vec![])) + } else { (None, None) }; - let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) - }; + if params.code.is_some() { + // part of substate that may be reverted + let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); - trace!(target: "executive", "res={:?}", res); + let res = { + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) + }; - // if there's tracing, make up trace_info's result with trace_output and some arithmetic. - if let Some((TraceAction::Call(ref mut c), _)) = trace_info { - c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: qed"))); + trace!(target: "executive", "res={:?}", res); + + // if there's tracing, make up trace_info's result with trace_output and some arithmetic. + if let Some((TraceAction::Call(ref mut c), _)) = trace_info { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: so should_trace: qed"))); + } + + trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); + + self.enact_result(&res, substate, unconfirmed_substate, trace_info); + trace!(target: "executive", "enacted: substate={:?}\n", substate); + res + } else { + // otherwise it's just a basic transaction, only do tracing, if necessary. + trace!(target: "executive", "Basic message (send funds) should_trace={}", should_trace); + self.state.clear_snapshot(); + if let Some((TraceAction::Call(ref mut c), _)) = trace_info { + c.result = Some((x!(0), vec![])); + } + substate.accrue_trace(if should_trace {Some(vec![])} else {None}, trace_info); + Ok(x!(0)) } - - trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); - - self.enact_result(&res, substate, unconfirmed_substate, trace_info); - trace!(target: "executive", "enacted: substate={:?}\n", substate); - res - } else { - // otherwise, nothing - self.state.clear_snapshot(); - Ok(params.gas) } } @@ -537,6 +545,7 @@ mod tests { //let next_address = contract_address(&address, &U256::zero()); let mut params = ActionParams::default(); params.address = address.clone(); + params.code_address = address.clone(); params.sender = sender.clone(); params.origin = sender.clone(); params.gas = U256::from(100_000); @@ -634,6 +643,7 @@ mod tests { assert_eq!(substate.subtraces, expected_trace); assert_eq!(gas_left, U256::from(96_776)); } + evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int} fn test_create_contract_value_too_high(factory: Factory) { // code: diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index c2924d1bb..7f8454a85 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -469,6 +469,44 @@ fn should_trace_call_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_trace_basic_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(0), vec![])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + #[test] fn should_not_trace_call_transaction_to_builtin() { init_log(); @@ -705,6 +743,95 @@ fn should_trace_call_with_subcall_transaction() { assert_eq!(result.trace, expected_trace); } +#[test] +fn should_trace_call_with_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(34061), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(69), + gas: x!(2300), + input: vec![], + result: Some((x!(0), vec![])) + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_not_trace_call_with_invalid_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(31761), vec![])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + #[test] fn should_trace_failed_subcall_transaction() { init_log(); From 068c0f3782c73cc0de0d8d30452495aa1a718fb1 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 21 Mar 2016 11:47:50 +0100 Subject: [PATCH 743/753] test for eth_getTransactionReceipt --- ethcore/src/client/ids.rs | 4 +- ethcore/src/client/test_client.rs | 12 +++++- ethcore/src/log_entry.rs | 2 +- ethcore/src/receipt.rs | 1 + rpc/src/v1/tests/eth.rs | 64 ++++++++++++++++++++++++++++++- rpc/src/v1/types/log.rs | 16 ++++---- rpc/src/v1/types/receipt.rs | 38 ++++++++++++++++++ 7 files changed, 122 insertions(+), 15 deletions(-) diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs index 303657a76..9bd59b177 100644 --- a/ethcore/src/client/ids.rs +++ b/ethcore/src/client/ids.rs @@ -20,7 +20,7 @@ use util::hash::H256; use header::BlockNumber; /// Uniquely identifies block. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Hash, Eq)] pub enum BlockId { /// Block's sha3. /// Querying by hash is always faster. @@ -34,7 +34,7 @@ pub enum BlockId { } /// Uniquely identifies transaction. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Hash, Eq)] pub enum TransactionId { /// Transaction's sha3. Hash(H256), diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 0adaae7e5..2b9f1051a 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -52,6 +52,8 @@ pub struct TestBlockChainClient { pub code: RwLock>, /// Execution result. pub execution_result: RwLock>, + /// Transaction receipts. + pub receipts: RwLock>, } #[derive(Clone)] @@ -87,12 +89,18 @@ impl TestBlockChainClient { storage: RwLock::new(HashMap::new()), code: RwLock::new(HashMap::new()), execution_result: RwLock::new(None), + receipts: RwLock::new(HashMap::new()), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } + /// Set the transaction receipt result + pub fn set_transaction_receipt(&self, id: TransactionId, receipt: LocalizedReceipt) { + self.receipts.write().unwrap().insert(id, receipt); + } + /// Set the execution result. pub fn set_execution_result(&self, result: Executed) { *self.execution_result.write().unwrap() = Some(result); @@ -224,8 +232,8 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn transaction_receipt(&self, _id: TransactionId) -> Option { - unimplemented!(); + fn transaction_receipt(&self, id: TransactionId) -> Option { + self.receipts.read().unwrap().get(&id).cloned() } fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index cf74a6df9..63e07730e 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -78,7 +78,7 @@ impl FromJson for LogEntry { } /// Log localized in a blockchain. -#[derive(Default, Debug, PartialEq)] +#[derive(Default, Debug, PartialEq, Clone)] pub struct LocalizedLogEntry { /// Plain log entry. pub entry: LogEntry, diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index 7f0b0d8dd..2fbd3f14c 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -76,6 +76,7 @@ impl HeapSizeOf for Receipt { } /// Receipt with additional info. +#[derive(Debug, Clone, PartialEq)] pub struct LocalizedReceipt { /// Transaction hash. pub transaction_hash: H256, diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 72235b390..4564076eb 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -14,12 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::str::FromStr; use std::collections::HashMap; use std::sync::{Arc, RwLock}; use jsonrpc_core::IoHandler; -use util::hash::{Address, H256}; +use util::hash::{Address, H256, FixedHash}; use util::numbers::{Uint, U256}; -use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed}; +use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId}; +use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; +use ethcore::receipt::LocalizedReceipt; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; @@ -382,6 +385,63 @@ fn rpc_eth_sign() { unimplemented!() } +#[test] +fn rpc_eth_transaction_receipt() { + let receipt = LocalizedReceipt { + transaction_hash: H256::zero(), + transaction_index: 0, + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: 0x4510c, + cumulative_gas_used: U256::from(0x20), + gas_used: U256::from(0x10), + contract_address: None, + logs: vec![LocalizedLogEntry { + entry: LogEntry { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: vec![], + }, + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: 0x4510c, + transaction_hash: H256::new(), + transaction_index: 0, + log_index: 1, + }] + }; + + let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap(); + let tester = EthTester::default(); + tester.client.set_transaction_receipt(TransactionId::Hash(hash), receipt); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","data":"0x","logIndex":"0x01","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"}],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"},"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_transaction_receipt_null() { + let tester = EthTester::default(); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + #[test] fn rpc_eth_compilers() { let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#; diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 0f5fdee15..c8dfb1aec 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -20,19 +20,19 @@ use v1::types::Bytes; #[derive(Debug, Serialize)] pub struct Log { - address: Address, - topics: Vec, - data: Bytes, + pub address: Address, + pub topics: Vec, + pub data: Bytes, #[serde(rename="blockHash")] - block_hash: H256, + pub block_hash: H256, #[serde(rename="blockNumber")] - block_number: U256, + pub block_number: U256, #[serde(rename="transactionHash")] - transaction_hash: H256, + pub transaction_hash: H256, #[serde(rename="transactionIndex")] - transaction_index: U256, + pub transaction_index: U256, #[serde(rename="logIndex")] - log_index: U256, + pub log_index: U256, } impl From for Log { diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index fa34d5df5..4bcfa3eb5 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -53,4 +53,42 @@ impl From for Receipt { } } +#[cfg(test)] +mod tests { + use serde_json; + use std::str::FromStr; + use util::numbers::*; + use v1::types::{Bytes, Log, Receipt}; + + #[test] + fn receipt_serialization() { + let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","logIndex":"0x01"}]}"#; + + let receipt = Receipt { + transaction_hash: H256::zero(), + transaction_index: U256::zero(), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + cumulative_gas_used: U256::from(0x20), + gas_used: U256::from(0x10), + contract_address: None, + logs: vec![Log { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: Bytes::new(vec![]), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + transaction_hash: H256::new(), + transaction_index: U256::zero(), + log_index: U256::one() + }] + }; + + let serialized = serde_json::to_string(&receipt).unwrap(); + assert_eq!(serialized, s); + } +} From 8ed8652296d549e6812b2b3d7299d5c8893d13f4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 21 Mar 2016 11:53:52 +0100 Subject: [PATCH 744/753] Reuse should_Trace. --- ethcore/src/executive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 8c34b8e39..a7bdb6a55 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -261,7 +261,7 @@ impl<'a> Executive<'a> { if params.code.is_some() { // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); + let mut unconfirmed_substate = Substate::new(should_trace); let res = { self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) From 8906b78b078d2fcd4baac30243c9c31a294f4f6d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 21 Mar 2016 11:56:11 +0100 Subject: [PATCH 745/753] Revert break. --- ethcore/src/executive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index a7bdb6a55..0081cdf1e 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -287,7 +287,7 @@ impl<'a> Executive<'a> { c.result = Some((x!(0), vec![])); } substate.accrue_trace(if should_trace {Some(vec![])} else {None}, trace_info); - Ok(x!(0)) + Ok(params.gas) } } } From 0e5395013a667820d495beb5654f799c6de739ae Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 21 Mar 2016 12:00:30 +0100 Subject: [PATCH 746/753] implemented eth_sendRawTransaction --- rpc/src/v1/impls/eth.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d7ee478bf..96f33fe2f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,13 +23,13 @@ use ethminer::{MinerService, AccountDetails}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; -use util::rlp::encode; +use util::rlp::{encode, UntrustedRlp, View}; use ethcore::client::*; use ethcore::block::IsBlock; use ethcore::views::*; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; -use ethcore::transaction::Transaction as EthTransaction; +use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction}; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner}; @@ -408,6 +408,33 @@ impl Eth for EthClient }) } + fn send_raw_transaction(&self, params: Params) -> Result { + from_params::<(Bytes, )>(params) + .and_then(|(raw_transaction, )| { + let decoded: Result = UntrustedRlp::new(&raw_transaction.to_vec()).as_val(); + match decoded { + Ok(signed_tx) => { + let miner = take_weak!(self.miner); + let client = take_weak!(self.client); + + let hash = signed_tx.hash(); + let import = miner.import_transactions(vec![signed_tx], |a: &Address| AccountDetails { + nonce: client.nonce(a), + balance: client.balance(a), + }); + match import.into_iter().collect::, _>>() { + Ok(_) => to_value(&hash), + Err(e) => { + warn!("Error sending transaction: {:?}", e); + to_value(&U256::zero()) + } + } + }, + Err(_) => { to_value(&U256::zero()) } + } + }) + } + fn call(&self, params: Params) -> Result { from_params::<(TransactionRequest, BlockNumber)>(params) .and_then(|(transaction_request, _block_number)| { From 2ab9d021586dbfaacb946be519ec1134e68edb8a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 21 Mar 2016 12:39:13 +0100 Subject: [PATCH 747/753] Fix test. --- ethcore/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 7f8454a85..21b0ad6ed 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -774,7 +774,7 @@ fn should_trace_call_with_basic_subcall_transaction() { value: x!(100), gas: x!(79000), input: vec![], - result: Some((x!(34061), vec![])) + result: Some((x!(31761), vec![])) }), subs: vec![Trace { depth: 1, From f2a0e244916a8b836a24102c316a729fa5ca4240 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 21 Mar 2016 20:29:35 +0100 Subject: [PATCH 748/753] removed outdated comment --- rpc/src/v1/impls/eth.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 96f33fe2f..fd35cb963 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -61,7 +61,6 @@ impl EthClient } } - impl EthClient where C: BlockChainClient, S: SyncProvider, @@ -371,7 +370,6 @@ impl Eth for EthClient } fn submit_hashrate(&self, params: Params) -> Result { - // TODO: Index should be U256. from_params::<(U256, H256)>(params).and_then(|(rate, id)| { self.external_miner.submit_hashrate(rate, id); to_value(&true) From 0cdac6de3cec85633afd3e28417d094dc979919f Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 22 Mar 2016 16:07:42 +0100 Subject: [PATCH 749/753] uncle --- ethcore/src/client/client.rs | 9 ++++++-- ethcore/src/client/ids.rs | 8 +++++++ ethcore/src/client/mod.rs | 7 ++++-- ethcore/src/client/test_client.rs | 6 ++++- rpc/src/v1/impls/eth.rs | 38 +++++++++++++++++++++++++++---- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b2254e285..61e3b4cd8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -21,7 +21,7 @@ use util::*; use util::panics::*; use views::BlockView; use error::*; -use header::{BlockNumber}; +use header::{BlockNumber, Header}; use state::State; use spec::Spec; use engine::Engine; @@ -36,7 +36,7 @@ use filter::Filter; use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; -use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; +use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient}; use env_info::EnvInfo; use executive::{Executive, Executed}; use receipt::LocalizedReceipt; @@ -549,6 +549,11 @@ impl BlockChainClient for Client where V: Verifier { self.transaction_address(id).and_then(|address| self.chain.transaction(&address)) } + fn uncle(&self, id: UncleId) -> Option
{ + let index = id.1; + self.block(id.0).and_then(|block| BlockView::new(&block).uncle_at(index)) + } + fn transaction_receipt(&self, id: TransactionId) -> Option { self.transaction_address(id).and_then(|address| { let t = self.chain.block(&address.block_hash) diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs index 9bd59b177..79302354f 100644 --- a/ethcore/src/client/ids.rs +++ b/ethcore/src/client/ids.rs @@ -42,3 +42,11 @@ pub enum TransactionId { /// Querying by block position is always faster. Location(BlockId, usize) } + +/// Uniquely identifies Uncle. +pub struct UncleId ( + /// Block id. + pub BlockId, + /// Position in block. + pub usize +); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 74b05652f..65733f3bf 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -23,7 +23,7 @@ mod test_client; pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; -pub use self::ids::{BlockId, TransactionId}; +pub use self::ids::{BlockId, TransactionId, UncleId}; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use executive::Executed; @@ -34,7 +34,7 @@ use util::numbers::U256; use blockchain::TreeRoute; use block_queue::BlockQueueInfo; use block::{ClosedBlock, SealedBlock}; -use header::BlockNumber; +use header::{BlockNumber, Header}; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; @@ -77,6 +77,9 @@ pub trait BlockChainClient : Sync + Send { /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; + /// Get uncle with given id. + fn uncle(&self, id: UncleId) -> Option
; + /// Get transaction receipt with given hash. fn transaction_receipt(&self, id: TransactionId) -> Option; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 2b9f1051a..1c3068f12 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -19,7 +19,7 @@ use util::*; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; -use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId}; +use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId}; use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; @@ -232,6 +232,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn uncle(&self, _id: UncleId) -> Option { + unimplemented!(); + } + fn transaction_receipt(&self, id: TransactionId) -> Option { self.receipts.read().unwrap().get(&id).cloned() } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index fd35cb963..6d8bd4b07 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -126,9 +126,36 @@ impl EthClient } } - fn uncle(&self, _block: BlockId, _index: usize) -> Result { - // TODO: implement! - Ok(Value::Null) + fn uncle(&self, id: UncleId) -> Result { + let client = take_weak!(self.client); + match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.hash())).map(|diff| (diff, u))) { + Some((difficulty, uncle)) => { + let block = Block { + hash: OptionalValue::Value(uncle.hash()), + parent_hash: uncle.parent_hash, + uncles_hash: uncle.uncles_hash, + author: uncle.author, + miner: uncle.author, + state_root: uncle.state_root, + transactions_root: uncle.transactions_root, + number: OptionalValue::Value(U256::from(uncle.number)), + gas_used: uncle.gas_used, + gas_limit: uncle.gas_limit, + logs_bloom: uncle.log_bloom, + timestamp: U256::from(uncle.timestamp), + difficulty: uncle.difficulty, + total_difficulty: difficulty, + receipts_root: uncle.receipts_root, + extra_data: Bytes::new(uncle.extra_data), + // todo: + nonce: H64::from(0), + uncles: vec![], + transactions: BlockTransactions::Hashes(vec![]), + }; + to_value(&block) + }, + None => Ok(Value::Null) + } } } @@ -303,12 +330,12 @@ impl Eth for EthClient fn uncle_by_block_hash_and_index(&self, params: Params) -> Result { from_params::<(H256, Index)>(params) - .and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value())) + .and_then(|(hash, index)| self.uncle(UncleId(BlockId::Hash(hash), index.value()))) } fn uncle_by_block_number_and_index(&self, params: Params) -> Result { from_params::<(BlockNumber, Index)>(params) - .and_then(|(number, index)| self.uncle(number.into(), index.value())) + .and_then(|(number, index)| self.uncle(UncleId(number.into(), index.value()))) } fn compilers(&self, params: Params) -> Result { @@ -434,6 +461,7 @@ impl Eth for EthClient } fn call(&self, params: Params) -> Result { + println!("params: {:?}", params); from_params::<(TransactionRequest, BlockNumber)>(params) .and_then(|(transaction_request, _block_number)| { let accounts = take_weak!(self.accounts); From a0cbe7cd7e4242b2d83ae44bc8a469ed9498edf1 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 22 Mar 2016 17:17:50 +0100 Subject: [PATCH 750/753] fixed eth_call, eth_sendTransaction and eth_estimateGas --- rpc/src/v1/impls/eth.rs | 107 +++++++++++++++--------- rpc/src/v1/types/call_request.rs | 106 +++++++++++++++++++++++ rpc/src/v1/types/mod.rs.in | 2 + rpc/src/v1/types/transaction_request.rs | 60 +------------ util/src/crypto.rs | 8 ++ 5 files changed, 185 insertions(+), 98 deletions(-) create mode 100644 rpc/src/v1/types/call_request.rs diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 6d8bd4b07..963afbecb 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -24,17 +24,26 @@ use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; use util::rlp::{encode, UntrustedRlp, View}; +use util::crypto::KeyPair; use ethcore::client::*; use ethcore::block::IsBlock; use ethcore::views::*; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; -use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction}; +use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log, Receipt}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner}; use util::keys::store::AccountProvider; +fn default_gas() -> U256 { + U256::from(21_000) +} + +fn default_gas_price() -> U256 { + shannon() * U256::from(50) +} + /// Eth rpc implementation. pub struct EthClient where C: BlockChainClient, @@ -157,6 +166,35 @@ impl EthClient None => Ok(Value::Null) } } + + fn sign_call(client: &Arc, accounts: &Arc, request: CallRequest) -> Option { + match request.from { + Some(ref from) => { + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(|| client.nonce(from)), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + + accounts.account_secret(from).ok().map(|secret| transaction.sign(&secret)) + }, + None => { + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(U256::zero), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + + KeyPair::create().ok().map(|kp| transaction.sign(kp.secret())) + } + } + } } impl Eth for EthClient @@ -217,7 +255,7 @@ impl Eth for EthClient fn gas_price(&self, params: Params) -> Result { match params { - Params::None => to_value(&(shannon() * U256::from(50))), + Params::None => to_value(&default_gas_price()), _ => Err(Error::invalid_params()) } } @@ -405,14 +443,22 @@ impl Eth for EthClient fn send_transaction(&self, params: Params) -> Result { from_params::<(TransactionRequest, )>(params) - .and_then(|(transaction_request, )| { + .and_then(|(request, )| { let accounts = take_weak!(self.accounts); - match accounts.account_secret(&transaction_request.from) { + match accounts.account_secret(&request.from) { Ok(secret) => { let miner = take_weak!(self.miner); let client = take_weak!(self.client); - let transaction: EthTransaction = transaction_request.into(); + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(|| client.nonce(&request.from)), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + let signed_transaction = transaction.sign(&secret); let hash = signed_transaction.hash(); @@ -461,47 +507,30 @@ impl Eth for EthClient } fn call(&self, params: Params) -> Result { - println!("params: {:?}", params); - from_params::<(TransactionRequest, BlockNumber)>(params) - .and_then(|(transaction_request, _block_number)| { + from_params::<(CallRequest, BlockNumber)>(params) + .and_then(|(request, _block_number)| { + let client = take_weak!(self.client); let accounts = take_weak!(self.accounts); - match accounts.account_secret(&transaction_request.from) { - Ok(secret) => { - let client = take_weak!(self.client); + let signed = Self::sign_call(&client, &accounts, request); + let output = signed.map(|tx| client.call(&tx) + .map(|e| Bytes::new(e.output)) + .unwrap_or(Bytes::default())); - let transaction: EthTransaction = transaction_request.into(); - let signed_transaction = transaction.sign(&secret); - - let output = client.call(&signed_transaction) - .map(|e| Bytes::new(e.output)) - .unwrap_or(Bytes::default()); - - to_value(&output) - }, - Err(_) => { to_value(&Bytes::default()) } - } + to_value(&output) }) } fn estimate_gas(&self, params: Params) -> Result { - from_params::<(TransactionRequest, BlockNumber)>(params) - .and_then(|(transaction_request, _block_number)| { + from_params::<(CallRequest, BlockNumber)>(params) + .and_then(|(request, _block_number)| { + let client = take_weak!(self.client); let accounts = take_weak!(self.accounts); - match accounts.account_secret(&transaction_request.from) { - Ok(secret) => { - let client = take_weak!(self.client); + let signed = Self::sign_call(&client, &accounts, request); + let output = signed.map(|tx| client.call(&tx) + .map(|e| e.gas_used + e.refunded) + .unwrap_or(U256::zero())); - let transaction: EthTransaction = transaction_request.into(); - let signed_transaction = transaction.sign(&secret); - - let gas_used = client.call(&signed_transaction) - .map(|e| e.gas_used + e.refunded) - .unwrap_or(U256::zero()); - - to_value(&gas_used) - }, - Err(_) => { to_value(&U256::zero()) } - } + to_value(&output) }) } } diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs new file mode 100644 index 000000000..a47d40eb3 --- /dev/null +++ b/rpc/src/v1/types/call_request.rs @@ -0,0 +1,106 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::hash::Address; +use util::numbers::U256; +use v1::types::Bytes; + +#[derive(Debug, Default, PartialEq, Deserialize)] +pub struct CallRequest { + pub from: Option
, + pub to: Option
, + #[serde(rename="gasPrice")] + pub gas_price: Option, + pub gas: Option, + pub value: Option, + pub data: Option, + pub nonce: Option, +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use serde_json; + use util::numbers::{Uint, U256}; + use util::hash::Address; + use ethcore::transaction::{Transaction, Action}; + use v1::types::Bytes; + use super::*; + + #[test] + fn transaction_request_deserialize() { + let s = r#"{ + "from":"0x0000000000000000000000000000000000000001", + "to":"0x0000000000000000000000000000000000000002", + "gasPrice":"0x1", + "gas":"0x2", + "value":"0x3", + "data":"0x123456", + "nonce":"0x4" + }"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from(1)), + to: Some(Address::from(2)), + gas_price: Some(U256::from(1)), + gas: Some(U256::from(2)), + value: Some(U256::from(3)), + data: Some(Bytes::new(vec![0x12, 0x34, 0x56])), + nonce: Some(U256::from(4)), + }); + } + + #[test] + fn transaction_request_deserialize2() { + let s = r#"{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()), + to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + gas_price: Some(U256::from_str("9184e72a000").unwrap()), + gas: Some(U256::from_str("76c0").unwrap()), + value: Some(U256::from_str("9184e72a").unwrap()), + data: Some(Bytes::new("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap())), + nonce: None + }); + } + + #[test] + fn transaction_request_deserialize_empty() { + let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from(1)), + to: None, + gas_price: None, + gas: None, + value: None, + data: None, + nonce: None, + }); + } +} diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 0121e4aea..06b07b146 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -24,6 +24,7 @@ mod optionals; mod sync; mod transaction; mod transaction_request; +mod call_request; mod receipt; pub use self::block::{Block, BlockTransactions}; @@ -36,5 +37,6 @@ pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; pub use self::transaction_request::TransactionRequest; +pub use self::call_request::CallRequest; pub use self::receipt::Receipt; diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index ed4dc19a2..a9ed8a3f4 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -15,8 +15,7 @@ // along with Parity. If not, see . use util::hash::Address; -use util::numbers::{Uint, U256}; -use ethcore::transaction::{Action, Transaction}; +use util::numbers::U256; use v1::types::Bytes; #[derive(Debug, Default, PartialEq, Deserialize)] @@ -31,19 +30,6 @@ pub struct TransactionRequest { pub nonce: Option, } -impl Into for TransactionRequest { - fn into(self) -> Transaction { - Transaction { - nonce: self.nonce.unwrap_or_else(U256::zero), - action: self.to.map_or(Action::Create, Action::Call), - gas: self.gas.unwrap_or_else(U256::zero), - gas_price: self.gas_price.unwrap_or_else(U256::zero), - value: self.value.unwrap_or_else(U256::zero), - data: self.data.map_or_else(Vec::new, |d| d.to_vec()), - } - } -} - #[cfg(test)] mod tests { use std::str::FromStr; @@ -55,50 +41,6 @@ mod tests { use v1::types::Bytes; use super::*; - #[test] - fn transaction_request_into_transaction() { - let tr = TransactionRequest { - from: Address::default(), - to: Some(Address::from(10)), - gas_price: Some(U256::from(20)), - gas: Some(U256::from(10_000)), - value: Some(U256::from(1)), - data: Some(Bytes::new(vec![10, 20])), - nonce: Some(U256::from(12)), - }; - - assert_eq!(Transaction { - nonce: U256::from(12), - action: Action::Call(Address::from(10)), - gas: U256::from(10_000), - gas_price: U256::from(20), - value: U256::from(1), - data: vec![10, 20], - }, tr.into()); - } - - #[test] - fn empty_transaction_request_into_transaction() { - let tr = TransactionRequest { - from: Address::default(), - to: None, - gas_price: None, - gas: None, - value: None, - data: None, - nonce: None, - }; - - assert_eq!(Transaction { - nonce: U256::zero(), - action: Action::Create, - gas: U256::zero(), - gas_price: U256::zero(), - value: U256::zero(), - data: vec![], - }, tr.into()); - } - #[test] fn transaction_request_deserialize() { let s = r#"{ diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 66e9f2edb..e5096a317 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -20,6 +20,7 @@ use numbers::*; use bytes::*; use secp256k1::{key, Secp256k1}; use rand::os::OsRng; +use sha3::Hashable; /// Secret key for secp256k1 EC operations. 256 bit generic "hash" data. pub type Secret = H256; @@ -135,15 +136,22 @@ impl KeyPair { public: p, }) } + /// Returns public key pub fn public(&self) -> &Public { &self.public } + /// Returns private key pub fn secret(&self) -> &Secret { &self.secret } + /// Returns address. + pub fn address(&self) -> Address { + Address::from(self.public.sha3()) + } + /// Sign a message with our secret key. pub fn sign(&self, message: &H256) -> Result { ec::sign(&self.secret, message) } } From 7624bcf49ec4eb0e3dccdef8daa51989546b2e4b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 22 Mar 2016 18:43:06 +0100 Subject: [PATCH 751/753] Increase threads to 4. --- parity/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index e029124c4..946e409bb 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -269,7 +269,9 @@ fn setup_rpc_server( } } } - Some(server.start_http(url, cors_domain, 1)) + // 4 is the number of threads which also happens to be the maximum number of concurrent + // connections our jsonrpc can manage. + Some(server.start_http(url, cors_domain, 4)) } #[cfg(not(feature = "rpc"))] From 0e026ed11ff7e3330c84965c6228d43aeffd298c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 22 Mar 2016 19:12:17 +0100 Subject: [PATCH 752/753] Fix author reporting. num_cpus for JSONRPC threads. --- Cargo.lock | 1 + Cargo.toml | 1 + miner/src/lib.rs | 8 +++++++- miner/src/miner.rs | 8 ++++++++ parity/main.rs | 5 ++--- rpc/src/v1/impls/eth.rs | 4 ++-- 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 56bd823c1..14ebabb6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ "ethsync 1.1.0", "fdlimit 0.1.0", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index e468799ea..f281cb854 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ time = "0.1" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } fdlimit = { path = "util/fdlimit" } daemonize = "0.2" +num_cpus = "0.2" number_prefix = "0.2" rpassword = "0.1" clippy = { version = "0.0.54", optional = true } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index ca25e3993..06faf057e 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -65,7 +65,7 @@ pub use transaction_queue::{TransactionQueue, AccountDetails}; pub use miner::{Miner}; use std::sync::Mutex; -use util::{H256, Address, Bytes}; +use util::{H256, Address, FixedHash, Bytes}; use ethcore::client::{BlockChainClient}; use ethcore::block::{ClosedBlock}; use ethcore::error::{Error}; @@ -77,6 +77,12 @@ pub trait MinerService : Send + Sync { /// Returns miner's status. fn status(&self) -> MinerStatus; + /// Get the author that we will seal blocks as. + fn author(&self) -> Address { Address::zero() } + + /// Get the extra_data that we will seal blocks wuth. + fn extra_data(&self) -> Bytes { vec![] } + /// Imports transactions to transaction queue. fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index e1b314d57..d4f6c8a00 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -146,6 +146,14 @@ impl MinerService for Miner { } } + fn author(&self) -> Address { + *self.author.read().unwrap() + } + + fn extra_data(&self) -> Bytes { + self.extra_data.read().unwrap().clone() + } + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails { let mut transaction_queue = self.transaction_queue.lock().unwrap(); diff --git a/parity/main.rs b/parity/main.rs index 946e409bb..731bba9a1 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -20,6 +20,7 @@ #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] extern crate docopt; +extern crate num_cpus; extern crate rustc_serialize; extern crate ethcore_util as util; extern crate ethcore; @@ -269,9 +270,7 @@ fn setup_rpc_server( } } } - // 4 is the number of threads which also happens to be the maximum number of concurrent - // connections our jsonrpc can manage. - Some(server.start_http(url, cors_domain, 4)) + Some(server.start_http(url, cors_domain, ::num_cpus::get())) } #[cfg(not(feature = "rpc"))] diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d7ee478bf..df21623fd 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -168,8 +168,8 @@ impl Eth for EthClient // TODO: do not hardcode author. fn author(&self, params: Params) -> Result { match params { - Params::None => to_value(&Address::new()), - _ => Err(Error::invalid_params()) + Params::None => to_value(&take_weak!(self.miner).author()), + _ => Err(Error::invalid_params()), } } From c2d2e4162467e88f96b34ae754ec8f494db3c422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 23 Mar 2016 12:23:50 +0100 Subject: [PATCH 753/753] Fixing future-current transactions clash --- miner/src/transaction_queue.rs | 100 +++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index a07395349..9abe80f1c 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -192,7 +192,12 @@ impl TransactionSet { /// Inserts `TransactionOrder` to this set fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) -> Option { self.by_priority.insert(order.clone()); - self.by_address.insert(sender, nonce, order) + let r = self.by_address.insert(sender, nonce, order); + // If transaction was replaced remove it from priority queue + if let Some(ref order) = r { + self.by_priority.remove(order); + } + r } /// Remove low priority transactions if there is more then specified by given `limit`. @@ -371,7 +376,6 @@ impl TransactionQueue { })); } - let vtx = try!(VerifiedTransaction::new(tx)); let account = fetch_account(&vtx.sender()); @@ -571,9 +575,20 @@ impl TransactionQueue { } Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash); + // Keep track of highest nonce stored in current self.last_nonces.insert(address, nonce); - // But maybe there are some more items waiting in future? + // Update nonces of transactions in future + self.update_future(&address, state_nonce); + // Maybe there are some more items waiting in future? self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); + // There might be exactly the same transaction waiting in future + // same (sender, nonce), but above function would not move it. + if let Some(order) = self.future.drop(&address, &nonce) { + // Let's insert that transaction to current (if it has higher gas_price) + let future_tx = self.by_hash.remove(&order.hash).unwrap(); + Self::replace_transaction(future_tx, state_nonce, &mut self.current, &mut self.by_hash); + } + // Also enforce the limit self.current.enforce_limit(&mut self.by_hash); trace!(target: "miner", "status: {:?}", self.status()); @@ -597,13 +612,11 @@ impl TransactionQueue { let new_fee = order.gas_price; if old_fee.cmp(&new_fee) == Ordering::Greater { // Put back old transaction since it has greater priority (higher gas_price) - set.by_address.insert(address, nonce, old); + set.insert(address, nonce, old); // and remove new one - set.by_priority.remove(&order); by_hash.remove(&hash); } else { // Make sure we remove old transaction entirely - set.by_priority.remove(&old); by_hash.remove(&old.hash); } } @@ -643,6 +656,18 @@ mod test { } } + /// Returns two transactions with identical (sender, nonce) but different hashes + fn new_similar_txs() -> (SignedTransaction, SignedTransaction) { + let keypair = KeyPair::create().unwrap(); + let secret = &keypair.secret(); + let nonce = U256::from(123); + let tx = new_unsigned_tx(nonce); + let mut tx2 = new_unsigned_tx(nonce); + tx2.gas_price = U256::from(2); + + (tx.sign(secret), tx2.sign(secret)) + } + fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) { let keypair = KeyPair::create().unwrap(); let secret = &keypair.secret(); @@ -693,6 +718,69 @@ mod test { assert_eq!(set.by_address.len(), 0); } + #[test] + fn should_replace_transaction_in_set() { + let mut set = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), + limit: 1 + }; + // Create two transactions with same nonce + // (same hash) + let (tx1, tx2) = new_txs(U256::from(0)); + let tx1 = VerifiedTransaction::new(tx1).unwrap(); + let tx2 = VerifiedTransaction::new(tx2).unwrap(); + let by_hash = { + let mut x = HashMap::new(); + let tx1 = VerifiedTransaction::new(tx1.transaction.clone()).unwrap(); + let tx2 = VerifiedTransaction::new(tx2.transaction.clone()).unwrap(); + x.insert(tx1.hash(), tx1); + x.insert(tx2.hash(), tx2); + x + }; + // Insert both transactions + let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + set.insert(tx1.sender(), tx1.nonce(), order1.clone()); + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + // Two different orders (imagine nonce changed in the meantime) + let order2 = TransactionOrder::for_transaction(&tx2, U256::one()); + set.insert(tx2.sender(), tx2.nonce(), order2.clone()); + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + + // then + assert_eq!(by_hash.len(), 1); + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + assert_eq!(set.by_priority.iter().next().unwrap().clone(), order2); + } + + #[test] + fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { + // given + let mut txq = TransactionQueue::new(); + let (tx, tx2) = new_similar_txs(); + let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance: + !U256::zero() }; + + // First insert one transaction to future + let res = txq.add(tx, &prev_nonce); + assert!(res.is_ok()); + assert_eq!(txq.status().future, 1); + + // now import second transaction to current + let res = txq.add(tx2.clone(), &default_nonce); + + // and then there should be only one transaction in current (the one with higher gas_price) + assert!(res.is_ok()); + assert_eq!(txq.status().pending, 1); + assert_eq!(txq.status().future, 0); + assert_eq!(txq.current.by_priority.len(), 1); + assert_eq!(txq.current.by_address.len(), 1); + assert_eq!(txq.top_transactions()[0], tx2); + } + #[test] fn should_import_tx() {