diff --git a/Cargo.lock b/Cargo.lock index 845c493fa..bd59e41fe 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" @@ -211,11 +223,13 @@ 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", "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)", @@ -228,6 +242,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/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/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/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/block.rs b/ethcore/src/block.rs index 70c6c2fb2..f5788baba 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 @@ -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, } @@ -178,10 +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.set_timestamp_now(); + 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.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); @@ -259,7 +261,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 +273,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 +284,40 @@ 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 } + /// 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_seal(&s.block.base.header) { + Err(_) => Err(s), + _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), + } + } /// 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 +339,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 +357,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 +372,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 +393,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] @@ -398,7 +405,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.deref(), 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 668c004e5..490a17995 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); @@ -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/best_block.rs b/ethcore/src/blockchain/best_block.rs index cbb219617..00c092713 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::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 98dac648d..ce639bfed 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::numbers::{U256,H256}; use header::BlockNumber; /// Brief info about inserted block. diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 0aba36a8e..185bcaad3 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); @@ -770,14 +776,15 @@ mod tests { use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; use tests::helpers::*; use devtools::*; - use blockchain::helpers::generators::ChainGenerator; + 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(); - let first = canon_chain.next().unwrap(); + 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(); @@ -805,20 +812,22 @@ 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 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 = 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 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()); @@ -893,22 +902,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); } } @@ -972,29 +983,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/bloom_indexer.rs b/ethcore/src/blockchain/bloom_indexer.rs index 74c679ba8..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::hash::H256; +use util::numbers::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/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/generator/generator.rs b/ethcore/src/blockchain/generator/generator.rs new file mode 100644 index 000000000..51e6294fc --- /dev/null +++ b/ethcore/src/blockchain/generator/generator.rs @@ -0,0 +1,169 @@ +// 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; +use util::numbers::U256; +use util::bytes::Bytes; +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 + Sized { + /// Should be called to create a fork of current iterator. + /// 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>; + /// 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 { + fn fork(&self, fork_number: usize) -> Fork where I: Clone { + Fork { + iter: self.clone(), + fork_number: fork_number + } + } + + fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self> { + Bloom { + iter: self, + bloom: bloom + } + } + + fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self> { + Complete { + iter: self, + finalizer: finalizer + } + } + + fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where ::Item: CompleteBlock { + self.complete(finalizer).next() + } +} + +/// Blockchain generator. +#[derive(Clone)] +pub struct ChainGenerator { + /// Next block number. + number: BlockNumber, + /// Next block difficulty. + difficulty: U256, +} + +impl ChainGenerator { + fn prepare_block(&self) -> Block { + let mut block = Block::default(); + block.header.number = self.number; + block.header.difficulty = self.difficulty; + block + } +} + +impl Default for ChainGenerator { + fn default() -> Self { + ChainGenerator { + number: 0, + difficulty: U256::from(1000), + } + } +} + +impl Iterator for ChainGenerator { + type Item = Block; + + fn next(&mut self) -> Option { + let block = self.prepare_block(); + self.number += 1; + Some(block) + } +} + +mod tests { + use util::hash::{H256, H2048}; + use util::sha3::Hashable; + use views::BlockView; + 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.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.generate(&mut finalizer).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(1); + + 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.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/helpers/generators.rs b/ethcore/src/blockchain/helpers/generators.rs deleted file mode 100644 index 75e7655eb..000000000 --- a/ethcore/src/blockchain/helpers/generators.rs +++ /dev/null @@ -1,154 +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 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/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; diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/blockchain/tree_route.rs index 1bd0e6f75..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::hash::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 f8ca06e66..6be2647d3 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::numbers::H256; use header::BlockNumber; use blockchain::block_info::BlockInfo; use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms}; 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); } }); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 611561c50..d442a3d88 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; @@ -179,7 +179,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; @@ -196,6 +196,11 @@ pub struct Client { report: RwLock, import_lock: Mutex<()>, panic_handler: Arc, + + // for sealing... + sealing_block: Mutex>, + author: RwLock
, + extra_data: RwLock, } const HISTORY: u64 = 1000; @@ -231,7 +236,10 @@ 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), + author: RwLock::new(Address::new()), + extra_data: RwLock::new(Vec::new()), })) } @@ -240,10 +248,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]) { @@ -256,10 +264,17 @@ 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; + // 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(); + 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(()); + } + // 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 { @@ -276,7 +291,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); @@ -305,6 +320,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; @@ -360,6 +377,10 @@ impl Client { } } + if self.chain_info().best_block_hash != original_best { + self.prepare_sealing(); + } + imported } @@ -406,8 +427,82 @@ impl Client { 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() + } + + /// 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) { + let h = self.chain.read().unwrap().best_block_hash(); + 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.clone()), + self.author(), + self.extra_data() + ); + + 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); + } + + /// 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.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 { fn block_header(&self, id: BlockId) -> Option { let chain = self.chain.read().unwrap(); @@ -484,12 +579,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..d607ce2e2 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() } @@ -76,9 +74,20 @@ pub trait Engine : Sync + Send { /// Verify a particular transaction is valid. fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } - /// Don't forget to call Super::populateFromParent when subclassing & overriding. + /// 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::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.difficulty = parent.difficulty; + header.gas_limit = parent.gas_limit; + header.note_dirty(); + } // 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/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 54f02524d..f9810b964 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() } @@ -106,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); } @@ -144,9 +142,10 @@ 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 +240,21 @@ 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))) + } + + /// 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) } } @@ -255,12 +265,20 @@ impl Ethash { } impl Header { - fn nonce(&self) -> H64 { + /// Get the none field of the header. + pub fn nonce(&self) -> H64 { decode(&self.seal()[1]) } - fn mix_hash(&self) -> H256 { + + /// 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()]; + } } #[cfg(test)] 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/header.rs b/ethcore/src/header.rs index 6ee682544..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) { 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 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/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"} diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index e35f651ee..c13678c38 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/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 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/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/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 diff --git a/parity/main.rs b/parity/main.rs index 3d0d183a3..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); @@ -354,7 +374,6 @@ impl Default for Informant { } impl Informant { - fn format_bytes(b: usize) -> String { match binary_prefix(b as f64) { Standalone(bytes) => format!("{} bytes", bytes), diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b9ca9deac..086fb19c1 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -9,12 +9,14 @@ build = "build.rs" [lib] [dependencies] +log = "0.3" 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" } +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 6d66a2c6d..d85286196 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,14 +15,17 @@ // 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::numbers::*; use util::sha3::*; +use util::standard::{RwLock, HashMap, Arc, Weak}; +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}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; @@ -30,7 +33,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 { @@ -38,7 +42,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()), } } @@ -125,7 +130,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()) } } @@ -133,7 +138,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()) } } @@ -220,6 +225,43 @@ 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 pow_hash = b.hash(); + let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); + let seed_hash = Ethash::get_seedhash(b.block().header().number()); + to_value(&(pow_hash, seed_hash, target)) + } + _ => Err(Error::invalid_params()) + } + }, + _ => Err(Error::invalid_params()) + } + } + + 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 seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; + let r = c.submit_seal(pow_hash, seal); + to_value(&r.is_ok()) + }) + } + + 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); + to_value(&true) + }) + } } /// Eth filter rpc implementation. 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/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/sync/src/chain.rs b/sync/src/chain.rs index 90f7b0d2a..1c3205a55 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -487,19 +487,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); @@ -645,16 +645,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(); @@ -674,74 +665,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); } } @@ -791,12 +796,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()); @@ -1189,8 +1194,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); @@ -1216,8 +1221,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(); @@ -1252,8 +1257,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); } @@ -1277,7 +1282,8 @@ impl ChainSync { good.for_each(|txs| { let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.remove_all(&txs); + let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); + transaction_queue.remove_all(&hashes); }); bad.for_each(|txs| { // populate sender @@ -1465,7 +1471,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()); @@ -1485,7 +1491,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()); @@ -1591,7 +1597,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)); @@ -1610,7 +1616,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 78663aa16..b388f508d 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -122,7 +122,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, BlocksWith::Uncle); net.sync(); @@ -148,7 +148,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, BlocksWith::Uncle); net.sync(); diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index fa6026477..4b7a22b1e 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::uint::{Uint, U256}; -use util::hash::{Address}; +use util::numbers::{Uint, U256}; +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]) { - for tx in txs { - self.remove(&tx); + pub fn remove_all(&mut self, transaction_hashes: &[H256]) { + for transaction_hash in transaction_hashes { + self.remove(&transaction_hash); } } - /// 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, transaction_hash: &H256) { + let transaction = self.by_hash.remove(transaction_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 @@ -355,29 +369,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::uint::{U256, Uint}; + 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 { @@ -409,6 +428,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 @@ -496,8 +555,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 @@ -519,7 +578,7 @@ mod test { assert_eq!(txq.status().pending, 3); // when - txq.remove(&tx); + txq.remove(&tx.hash()); // then let stats = txq.status(); @@ -609,14 +668,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); } 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 97% rename from util/src/uint.rs rename to util/bigint/src/uint.rs index 88256d5f2..a70997dc5 100644 --- a/util/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -36,10 +36,19 @@ //! 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::str::{FromStr}; +use std::convert::From; +use std::hash::{Hash, Hasher}; +use std::ops::*; +use std::cmp::*; + use serde; +use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; + macro_rules! impl_map_from { ($thing:ident, $from:ty, $to:ty) => { @@ -51,7 +60,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 +97,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 +173,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 +182,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 +258,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 +378,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 +389,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 +423,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 +786,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 +1091,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 +1230,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); @@ -1275,6 +1266,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; @@ -1338,6 +1356,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}; @@ -1982,6 +2003,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); 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..b2a06c4b9 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -19,10 +19,9 @@ 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] diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 2d5516b6f..66e9f2edb 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; @@ -151,8 +150,7 @@ impl KeyPair { /// EC functions pub mod ec { - use hash::*; - use uint::*; + use numbers::*; 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..73fa33b47 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; @@ -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 { @@ -595,7 +597,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 +633,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/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 } } 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()); diff --git a/util/src/lib.rs b/util/src/lib.rs index ea60418db..8594e6f40 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/misc.rs b/util/src/misc.rs index 289f1c50c..39ccbf2da 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; @@ -69,5 +70,19 @@ 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()) +} + +/// 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_version::version())); + s.append(&&Target::os()[0..2]); + s.out() } \ No newline at end of file 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() { 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) } }