Merge branch 'tx_queue_integration' into tx_queue_rpc

This commit is contained in:
Tomasz Drwięga 2016-03-04 12:34:34 +01:00
commit 410bd263dd
66 changed files with 1379 additions and 710 deletions

15
Cargo.lock generated
View File

@ -44,6 +44,18 @@ dependencies = [
"syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
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]] [[package]]
name = "bitflags" name = "bitflags"
version = "0.3.3" version = "0.3.3"
@ -211,11 +223,13 @@ name = "ethcore-rpc"
version = "0.9.99" version = "0.9.99"
dependencies = [ dependencies = [
"clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 0.9.99",
"ethcore 0.9.99", "ethcore 0.9.99",
"ethcore-util 0.9.99", "ethcore-util 0.9.99",
"ethsync 0.9.99", "ethsync 0.9.99",
"jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-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 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -228,6 +242,7 @@ name = "ethcore-util"
version = "0.9.99" version = "0.9.99"
dependencies = [ dependencies = [
"arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -172,7 +172,8 @@ fn get_data_size(block_number: u64) -> usize {
} }
#[inline] #[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 epochs = block_number / ETHASH_EPOCH_LENGTH;
let mut ret: H256 = [0u8; 32]; let mut ret: H256 = [0u8; 32];
for _ in 0..epochs { for _ in 0..epochs {

View File

@ -24,7 +24,7 @@ mod compute;
use std::mem; use std::mem;
use compute::Light; 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}; use std::sync::{Arc, Mutex};
@ -35,7 +35,7 @@ struct LightCache {
prev: Option<Arc<Light>>, prev: Option<Arc<Light>>,
} }
/// Lighy/Full cache manager /// Light/Full cache manager.
pub struct EthashManager { pub struct EthashManager {
cache: Mutex<LightCache>, cache: Mutex<LightCache>,
} }

@ -1 +1 @@
Subproject commit f32954b3ddb5af2dc3dc9ec6d9a28bee848fdf70 Subproject commit 99afe8f5aad7bca5d0f1b1685390a4dea32d73c3

View File

@ -15,9 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Evm input params. //! Evm input params.
use util::hash::*; use common::*;
use util::uint::*;
use util::bytes::*;
/// Transaction value /// Transaction value
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@ -21,7 +21,7 @@
use common::*; use common::*;
use engine::*; use engine::*;
use state::*; use state::*;
use verification::PreVerifiedBlock; use verification::PreverifiedBlock;
/// A block, encoded as it is on the block chain. /// A block, encoded as it is on the block chain.
// TODO: rename to Block // 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, /// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
/// and collected the uncles. /// and collected the uncles.
/// ///
/// There is no function available to push a transaction. If you want that you'll need to `reopen()` it. /// There is no function available to push a transaction.
pub struct ClosedBlock<'x> { pub struct ClosedBlock {
open_block: OpenBlock<'x>, block: ExecutedBlock,
uncle_bytes: Bytes, uncle_bytes: Bytes,
} }
@ -178,10 +178,12 @@ impl<'x> OpenBlock<'x> {
last_hashes: last_hashes, last_hashes: last_hashes,
}; };
r.block.base.header.set_number(parent.number() + 1); r.block.base.header.parent_hash = parent.hash();
r.block.base.header.set_author(author); r.block.base.header.number = parent.number + 1;
r.block.base.header.set_extra_data(extra_data); r.block.base.header.author = author;
r.block.base.header.set_timestamp_now(); 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.populate_from_parent(&mut r.block.base.header, parent);
engine.on_new_block(&mut r.block); 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. /// 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; let mut s = self;
s.engine.on_close_block(&mut s.block); 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()); 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.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used);
s.block.base.header.note_dirty(); 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 } fn block(&self) -> &ExecutedBlock { &self.block }
} }
impl<'x> IsBlock for ClosedBlock<'x> { impl<'x> IsBlock for ClosedBlock {
fn block(&self) -> &ExecutedBlock { &self.open_block.block } fn block(&self) -> &ExecutedBlock { &self.block }
} }
impl<'x> ClosedBlock<'x> { impl ClosedBlock {
fn new(open_block: OpenBlock<'x>, uncle_bytes: Bytes) -> Self {
ClosedBlock {
open_block: open_block,
uncle_bytes: uncle_bytes,
}
}
/// Get the hash of the header without seal arguments. /// Get the hash of the header without seal arguments.
pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) } pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) }
/// Provide a valid seal in order to turn this into a `SealedBlock`. /// Provide a valid seal in order to turn this into a `SealedBlock`.
/// ///
/// NOTE: This does not check the validity of `seal` with the engine. /// NOTE: This does not check the validity of `seal` with the engine.
pub fn seal(self, seal: Vec<Bytes>) -> Result<SealedBlock, BlockError> { pub fn seal(self, engine: &Engine, seal: Vec<Bytes>) -> Result<SealedBlock, BlockError> {
let mut s = self; let mut s = self;
if seal.len() != s.open_block.engine.seal_fields() { if seal.len() != engine.seal_fields() {
return Err(BlockError::InvalidSealArity(Mismatch{expected: s.open_block.engine.seal_fields(), found: seal.len()})); return Err(BlockError::InvalidSealArity(Mismatch{expected: engine.seal_fields(), found: seal.len()}));
} }
s.open_block.block.base.header.set_seal(seal); s.block.base.header.set_seal(seal);
Ok(SealedBlock { block: s.open_block.block, uncle_bytes: s.uncle_bytes }) Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes })
} }
/// Turn this back into an `OpenBlock`. /// Provide a valid seal in order to turn this into a `SealedBlock`.
pub fn reopen(self) -> OpenBlock<'x> { self.open_block } /// 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<Bytes>) -> Result<SealedBlock, ClosedBlock> {
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. /// 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 { impl SealedBlock {
@ -332,7 +339,7 @@ impl IsBlock for SealedBlock {
} }
/// Enact the block given by block header, transactions and uncles /// 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<ClosedBlock<'x>, Error> { pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
{ {
if ::log::max_log_level() >= ::log::LogLevel::Trace { if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce()); let s = State::from_existing(db.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 /// 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<ClosedBlock<'x>, Error> { pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
let block = BlockView::new(block_bytes); let block = BlockView::new(block_bytes);
let header = block.header(); let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) 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 /// 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<ClosedBlock<'x>, Error> { pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result<ClosedBlock, Error> {
let view = BlockView::new(&block.bytes); let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) enact(&block.header, &block.transactions, &view.uncles(), engine, 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 /// 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<SealedBlock, Error> { pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view(); 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)] #[cfg(test)]
@ -386,7 +393,7 @@ mod tests {
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]); let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]);
let b = b.close(); let b = b.close();
let _ = b.seal(vec![]); let _ = b.seal(engine.deref(), vec![]);
} }
#[test] #[test]
@ -398,7 +405,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
engine.spec().ensure_db_good(&mut db); 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_bytes = b.rlp_bytes();
let orig_db = b.drain(); let orig_db = b.drain();

View File

@ -28,7 +28,7 @@ use service::*;
use client::BlockStatus; use client::BlockStatus;
use util::panics::*; 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_MEM_LIMIT: usize = 16384;
const MIN_QUEUE_LIMIT: usize = 512; const MIN_QUEUE_LIMIT: usize = 512;
@ -105,14 +105,14 @@ pub struct BlockQueue {
max_mem_use: usize, max_mem_use: usize,
} }
struct UnVerifiedBlock { struct UnverifiedBlock {
header: Header, header: Header,
bytes: Bytes, bytes: Bytes,
} }
struct VerifyingBlock { struct VerifyingBlock {
hash: H256, hash: H256,
block: Option<PreVerifiedBlock>, block: Option<PreverifiedBlock>,
} }
struct QueueSignal { struct QueueSignal {
@ -134,8 +134,8 @@ impl QueueSignal {
#[derive(Default)] #[derive(Default)]
struct Verification { struct Verification {
unverified: VecDeque<UnVerifiedBlock>, unverified: VecDeque<UnverifiedBlock>,
verified: VecDeque<PreVerifiedBlock>, verified: VecDeque<PreverifiedBlock>,
verifying: VecDeque<VerifyingBlock>, verifying: VecDeque<VerifyingBlock>,
bad: HashSet<H256>, bad: HashSet<H256>,
} }
@ -244,7 +244,7 @@ impl BlockQueue {
} }
} }
fn drain_verifying(verifying: &mut VecDeque<VerifyingBlock>, verified: &mut VecDeque<PreVerifiedBlock>, bad: &mut HashSet<H256>) { fn drain_verifying(verifying: &mut VecDeque<VerifyingBlock>, verified: &mut VecDeque<PreverifiedBlock>, bad: &mut HashSet<H256>) {
while !verifying.is_empty() && verifying.front().unwrap().block.is_some() { while !verifying.is_empty() && verifying.front().unwrap().block.is_some() {
let block = verifying.pop_front().unwrap().block.unwrap(); let block = verifying.pop_front().unwrap().block.unwrap();
if bad.contains(&block.header.parent_hash) { if bad.contains(&block.header.parent_hash) {
@ -289,31 +289,31 @@ impl BlockQueue {
let header = BlockView::new(&bytes).header(); let header = BlockView::new(&bytes).header();
let h = header.hash(); let h = header.hash();
if self.processing.read().unwrap().contains(&h) { if self.processing.read().unwrap().contains(&h) {
return Err(ImportError::AlreadyQueued); return Err(x!(ImportError::AlreadyQueued));
} }
{ {
let mut verification = self.verification.lock().unwrap(); let mut verification = self.verification.lock().unwrap();
if verification.bad.contains(&h) { if verification.bad.contains(&h) {
return Err(ImportError::Bad(None)); return Err(x!(ImportError::KnownBad));
} }
if verification.bad.contains(&header.parent_hash) { if verification.bad.contains(&header.parent_hash) {
verification.bad.insert(h.clone()); 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()) { match verify_block_basic(&header, &bytes, self.engine.deref().deref()) {
Ok(()) => { Ok(()) => {
self.processing.write().unwrap().insert(h.clone()); 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(); self.more_to_verify.notify_all();
Ok(h) Ok(h)
}, },
Err(err) => { Err(err) => {
warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err);
self.verification.lock().unwrap().bad.insert(h.clone()); self.verification.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 /// Removes up to `max` verified blocks from the queue
pub fn drain(&mut self, max: usize) -> Vec<PreVerifiedBlock> { pub fn drain(&mut self, max: usize) -> Vec<PreverifiedBlock> {
let mut verification = self.verification.lock().unwrap(); let mut verification = self.verification.lock().unwrap();
let count = min(max, verification.verified.len()); let count = min(max, verification.verified.len());
let mut result = Vec::with_capacity(count); let mut result = Vec::with_capacity(count);
@ -455,7 +455,7 @@ mod tests {
match duplicate_import { match duplicate_import {
Err(e) => { Err(e) => {
match e { match e {
ImportError::AlreadyQueued => {}, Error::Import(ImportError::AlreadyQueued) => {},
_ => { panic!("must return AlreadyQueued error"); } _ => { panic!("must return AlreadyQueued error"); }
} }
} }

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::hash::H256; use util::numbers::{U256,H256};
use util::uint::U256;
use header::BlockNumber; use header::BlockNumber;
/// Best block info. /// Best block info.

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::hash::H256; use util::numbers::{U256,H256};
use util::uint::U256;
use header::BlockNumber; use header::BlockNumber;
/// Brief info about inserted block. /// Brief info about inserted block.

View File

@ -473,6 +473,12 @@ impl BlockChain {
self.extras_db.write(batch).unwrap(); 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<Header> {
// TODO
Vec::new()
}
/// Get inserted block info which is critical to preapre extras updates. /// Get inserted block info which is critical to preapre extras updates.
fn block_info(&self, block_bytes: &[u8]) -> BlockInfo { fn block_info(&self, block_bytes: &[u8]) -> BlockInfo {
let block = BlockView::new(block_bytes); let block = BlockView::new(block_bytes);
@ -770,14 +776,15 @@ mod tests {
use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; use blockchain::{BlockProvider, BlockChain, BlockChainConfig};
use tests::helpers::*; use tests::helpers::*;
use devtools::*; use devtools::*;
use blockchain::helpers::generators::ChainGenerator; use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
use views::BlockView; use views::BlockView;
#[test] #[test]
fn basic_blockchain_insert() { fn basic_blockchain_insert() {
let mut canon_chain = ChainGenerator::default(); let mut canon_chain = ChainGenerator::default();
let genesis = canon_chain.next().unwrap(); let mut finalizer = BlockFinalizer::default();
let first = canon_chain.next().unwrap(); 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 genesis_hash = BlockView::new(&genesis).header_view().sha3();
let first_hash = BlockView::new(&first).header_view().sha3(); let first_hash = BlockView::new(&first).header_view().sha3();
@ -805,20 +812,22 @@ mod tests {
#[test] #[test]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn test_small_fork() { fn test_small_fork() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); let mut canon_chain = ChainGenerator::default();
let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); let mut finalizer = BlockFinalizer::default();
let b2 = "f902ccf901f9a0437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); let genesis = canon_chain.generate(&mut finalizer).unwrap();
let b3a = "f90261f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a09dc4b1357c0b7b8108f8a098f4f9a1a274957bc9ebc22a9ae67ae81739e5b19ca007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882524d84562791eb80a074861666bd346c025889745c793b91ab9cd1e2ca19b5cf3c50d04d135b0a4d2b8809fe9587ea4cdc04f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba06fd84874d36d5de9e8e48978c03619b53a96b7ae0a4cd1ac118f103098b44801a00572596974dd7df4f9f69bd7456585618c568d8434ef6453391b89281ce12ae1c0".from_hex().unwrap(); let b1 = canon_chain.generate(&mut finalizer).unwrap();
let b3b = "f90265f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ab87dc338bfd6f662b1cd90bc0c9e40a1b2146a095312393c9e13ce3a5008b09a0e609b7a7d4b8a2403ec1268627ecd98783627246e8f1b26addb3ff504f76a054a0592fabf92476512952db3a69a2481a42912e668a1ee28c4c322e703bb665f8beb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882a1f084562791ee80a0fe7098fa7e4ac5d637eea81fb23f8f78346826dbab430068dd9a249d0afa99818853e1a6b201ae3545f866f86402018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d0284c04062261ca06edc9ce8e7da4cc34067beb325dcad59e5655a164a5100a50bc3eb681b12c716a0abf9053d5de65b1be81fe50d327b84de685efbeecea34e7b747180a6c6023e44c0".from_hex().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 genesis_hash = BlockView::new(&genesis).header_view().sha3();
let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap(); let b1_hash= BlockView::new(&b1).header_view().sha3();
let b2_hash = H256::from_str("36fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781a").unwrap(); let b2_hash= BlockView::new(&b2).header_view().sha3();
let b3a_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap(); let b3a_hash= BlockView::new(&b3a).header_view().sha3();
let b3b_hash = H256::from_str("bf72270ae0d95c9ea39a6adab994793fddb8c10fba7391e26279474124605d54").unwrap(); let b3b_hash= BlockView::new(&b3b).header_view().sha3();
// b3a is a part of canon chain, whereas b3b is part of sidechain // 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 temp = RandomTempPath::new();
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
@ -893,22 +902,24 @@ mod tests {
#[test] #[test]
fn test_reopen_blockchain_db() { fn test_reopen_blockchain_db() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); let mut canon_chain = ChainGenerator::default();
let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); let mut finalizer = BlockFinalizer::default();
let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap(); let genesis = canon_chain.generate(&mut finalizer).unwrap();
let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").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 temp = RandomTempPath::new();
{ {
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
assert_eq!(bc.best_block_hash(), genesis_hash); assert_eq!(bc.best_block_hash(), genesis_hash);
bc.insert_block(&b1, vec![]); bc.insert_block(&first, vec![]);
assert_eq!(bc.best_block_hash(), b1_hash); assert_eq!(bc.best_block_hash(), first_hash);
} }
{ {
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); 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] #[test]
fn test_bloom_filter_simple() { fn test_bloom_filter_simple() {
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); // TODO: From here
// 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();
let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap(); let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap();
let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_ba = H2048::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").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 temp = RandomTempPath::new();
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::hash::H256; use util::numbers::H256;
use chainfilter::BloomIndex; use chainfilter::BloomIndex;
/// Represents location of block bloom in extras database. /// Represents location of block bloom in extras database.

View File

@ -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 <http://www.gnu.org/licenses/>.
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<SignedTransaction>,
pub uncles: Vec<Header>
}
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()
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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, <I as Iterator>::Item: WithBloom {
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|item| item.with_bloom(self.bloom.clone()))
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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, <I as Iterator>::Item: CompleteBlock {
type Item = Bytes;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
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
})
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
pub trait Forkable {
fn fork(self, fork_number: usize) -> Self where Self: Sized;
}
pub struct Fork<I> {
pub iter: I,
pub fork_number: usize,
}
impl<I> Clone for Fork<I> where I: Iterator + Clone {
fn clone(&self) -> Self {
Fork {
iter: self.iter.clone(),
fork_number: self.fork_number
}
}
}
impl<I> Iterator for Fork<I> where I: Iterator, <I as Iterator>::Item: Forkable {
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|item| item.fork(self.fork_number))
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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<Self> 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<Bytes> where Self::Item: CompleteBlock;
}
impl<I> ChainIterator for I where I: Iterator + Sized {
fn fork(&self, fork_number: usize) -> Fork<Self> 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<Bytes> where <I as Iterator>::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<Self::Item> {
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);
}
}

View File

@ -14,4 +14,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
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};

View File

@ -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 <http://www.gnu.org/licenses/>.
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<Self::Item>;
}
/// Helper structure, used for encoding blocks.
#[derive(Default)]
struct Block {
header: Header,
transactions: Vec<SignedTransaction>,
uncles: Vec<Header>
}
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<Self::Item> {
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<Self::Item> {
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());
}
}

View File

@ -24,7 +24,7 @@ mod cache;
mod tree_route; mod tree_route;
mod update; mod update;
#[cfg(test)] #[cfg(test)]
mod helpers; mod generator;
pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig};
pub use self::cache::CacheSize; pub use self::cache::CacheSize;

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::hash::H256; use util::numbers::H256;
/// Represents a tree route between `from` block and `to` block: /// Represents a tree route between `from` block and `to` block:
#[derive(Debug)] #[derive(Debug)]

View File

@ -1,5 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use util::hash::H256; use util::numbers::H256;
use header::BlockNumber; use header::BlockNumber;
use blockchain::block_info::BlockInfo; use blockchain::block_info::BlockInfo;
use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms}; use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms};

View File

@ -88,7 +88,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource
None => return None, None => return None,
Some(level_bloom) => match level { Some(level_bloom) => match level {
// if we are on the lowest 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 // take the value if its smaller than to_block
true if level_bloom.contains(bloom) => Some(vec![offset]), true if level_bloom.contains(bloom) => Some(vec![offset]),
// return None if it is is equal to to_block // return None if it is is equal to to_block

View File

@ -81,13 +81,13 @@ fn test_topic_basic_search() {
{ {
let filter = ChainFilter::new(&cache, index_size, bloom_levels); 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); assert_eq!(blocks.len(), 0);
} }
{ {
let filter = ChainFilter::new(&cache, index_size, bloom_levels); 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.len(), 1);
assert_eq!(blocks[0], 23); assert_eq!(blocks[0], 23);
} }
@ -235,11 +235,11 @@ fn test_chainfilter_real_data_short_searches() {
for_each_log(include_bytes!("logs.txt"), | block_number, address, topics | { for_each_log(include_bytes!("logs.txt"), | block_number, address, topics | {
println!("block_number: {:?}", block_number); println!("block_number: {:?}", block_number);
let filter = ChainFilter::new(&cache, index_size, bloom_levels); 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); assert_eq!(blocks.len(), 1);
for (i, topic) in topics.iter().enumerate() { for (i, topic) in topics.iter().enumerate() {
println!("topic: {:?}", i); 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); assert_eq!(blocks.len(), 1);
} }
}); });

View File

@ -21,7 +21,7 @@ use util::panics::*;
use blockchain::{BlockChain, BlockProvider}; use blockchain::{BlockChain, BlockProvider};
use views::BlockView; use views::BlockView;
use error::*; use error::*;
use header::{BlockNumber, Header}; use header::{BlockNumber};
use state::State; use state::State;
use spec::Spec; use spec::Spec;
use engine::Engine; use engine::Engine;
@ -179,7 +179,7 @@ pub struct ClientReport {
impl ClientReport { impl ClientReport {
/// Alter internal reporting to reflect the additional `block` has been processed. /// 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.blocks_imported += 1;
self.transactions_applied += block.transactions.len(); self.transactions_applied += block.transactions.len();
self.gas_processed = self.gas_processed + block.header.gas_used; self.gas_processed = self.gas_processed + block.header.gas_used;
@ -196,6 +196,11 @@ pub struct Client {
report: RwLock<ClientReport>, report: RwLock<ClientReport>,
import_lock: Mutex<()>, import_lock: Mutex<()>,
panic_handler: Arc<PanicHandler>, panic_handler: Arc<PanicHandler>,
// for sealing...
sealing_block: Mutex<Option<ClosedBlock>>,
author: RwLock<Address>,
extra_data: RwLock<Bytes>,
} }
const HISTORY: u64 = 1000; const HISTORY: u64 = 1000;
@ -231,7 +236,10 @@ impl Client {
block_queue: RwLock::new(block_queue), block_queue: RwLock::new(block_queue),
report: RwLock::new(Default::default()), report: RwLock::new(Default::default()),
import_lock: Mutex::new(()), 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(); 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(); let mut last_hashes = LastHashes::new();
last_hashes.resize(256, H256::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(); let chain = self.chain.read().unwrap();
for i in 0..255 { for i in 0..255 {
match chain.block_details(&last_hashes[i]) { match chain.block_details(&last_hashes[i]) {
@ -256,10 +264,17 @@ impl Client {
last_hashes last_hashes
} }
fn check_and_close_block(&self, block: &PreVerifiedBlock) -> Result<ClosedBlock, ()> { fn check_and_close_block(&self, block: &PreverifiedBlock) -> Result<ClosedBlock, ()> {
let engine = self.engine.deref().deref(); let engine = self.engine.deref().deref();
let header = &block.header; 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 // Verify Block Family
let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref()); let verify_family_result = verify_block_family(&header, &block.bytes, engine, self.chain.read().unwrap().deref());
if let Err(e) = verify_family_result { if let Err(e) = verify_family_result {
@ -276,7 +291,7 @@ impl Client {
// Enact Verified Block // Enact Verified Block
let parent = chain_has_parent.unwrap(); 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 db = self.state_db.lock().unwrap().clone();
let enact_result = enact_verified(&block, engine, db, &parent, last_hashes); 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 _import_lock = self.import_lock.lock();
let blocks = self.block_queue.write().unwrap().drain(max_blocks_to_import); 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 { for block in blocks {
let header = &block.header; let header = &block.header;
@ -360,6 +377,10 @@ impl Client {
} }
} }
if self.chain_info().best_block_hash != original_best {
self.prepare_sealing();
}
imported imported
} }
@ -406,8 +427,82 @@ impl Client {
BlockId::Latest => Some(self.chain.read().unwrap().best_block_number()) 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<Option<ClosedBlock>> {
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<Bytes>) -> 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 { impl BlockChainClient for Client {
fn block_header(&self, id: BlockId) -> Option<Bytes> { fn block_header(&self, id: BlockId) -> Option<Bytes> {
let chain = self.chain.read().unwrap(); let chain = self.chain.read().unwrap();
@ -484,12 +579,14 @@ impl BlockChainClient for Client {
} }
fn import_block(&self, bytes: Bytes) -> ImportResult { fn import_block(&self, bytes: Bytes) -> ImportResult {
let header = BlockView::new(&bytes).header(); {
if self.chain.read().unwrap().is_known(&header.hash()) { let header = BlockView::new(&bytes).header_view();
return Err(ImportError::AlreadyInChain); 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())));
} }
if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown {
return Err(ImportError::UnknownParent);
} }
self.block_queue.write().unwrap().import_block(bytes) self.block_queue.write().unwrap().import_block(bytes)
} }

View File

@ -30,8 +30,6 @@ pub trait Engine : Sync + Send {
/// The number of additional header fields required for this engine. /// The number of additional header fields required for this engine.
fn seal_fields(&self) -> usize { 0 } 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`. /// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() } fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() }
@ -76,9 +74,20 @@ pub trait Engine : Sync + Send {
/// Verify a particular transaction is valid. /// Verify a particular transaction is valid.
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } 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. // 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 // 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. // from Spec into here and removing the Spec::builtins field.

View File

@ -131,25 +131,14 @@ pub enum BlockError {
#[derive(Debug)] #[derive(Debug)]
/// Import to the block queue result /// Import to the block queue result
pub enum ImportError { pub enum ImportError {
/// Bad block detected /// Already in the block chain.
Bad(Option<Error>),
/// Already in the block chain
AlreadyInChain, AlreadyInChain,
/// Already in the block queue /// Already in the block queue.
AlreadyQueued, AlreadyQueued,
/// Unknown parent /// Already marked as bad from a previous import (could mean parent is bad).
UnknownParent, KnownBad,
} }
impl From<Error> for ImportError {
fn from(err: Error) -> ImportError {
ImportError::Bad(Some(err))
}
}
/// Result of import block operation.
pub type ImportResult = Result<H256, ImportError>;
#[derive(Debug)] #[derive(Debug)]
/// General error type which should be capable of representing all errors in ethcore. /// General error type which should be capable of representing all errors in ethcore.
pub enum Error { pub enum Error {
@ -163,14 +152,29 @@ pub enum Error {
Execution(ExecutionError), Execution(ExecutionError),
/// Error concerning transaction processing. /// Error concerning transaction processing.
Transaction(TransactionError), 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<H256, Error>;
impl From<TransactionError> for Error { impl From<TransactionError> for Error {
fn from(err: TransactionError) -> Error { fn from(err: TransactionError) -> Error {
Error::Transaction(err) Error::Transaction(err)
} }
} }
impl From<ImportError> for Error {
fn from(err: ImportError) -> Error {
Error::Import(err)
}
}
impl From<BlockError> for Error { impl From<BlockError> for Error {
fn from(err: BlockError) -> Error { fn from(err: BlockError) -> Error {
Error::Block(err) Error::Block(err)

View File

@ -74,8 +74,6 @@ impl Engine for Ethash {
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) } fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
// Two fields - mix // Two fields - mix
fn seal_fields(&self) -> usize { 2 } 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`. /// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info(&self, _header: &Header) -> HashMap<String, String> { HashMap::new() } fn extra_info(&self, _header: &Header) -> HashMap<String, String> { 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) 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); // info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit);
} }
@ -146,7 +144,8 @@ impl Engine for Ethash {
let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty( let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty(
&Ethash::to_ethash(header.bare_hash()), &Ethash::to_ethash(header.bare_hash()),
header.nonce().low_u64(), header.nonce().low_u64(),
&Ethash::to_ethash(header.mix_hash())))); &Ethash::to_ethash(header.mix_hash())
)));
if difficulty < header.difficulty { if difficulty < header.difficulty {
return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty }))); return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty })));
} }
@ -241,10 +240,21 @@ impl Ethash {
target 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()))) 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 { fn to_ethash(hash: H256) -> EH256 {
unsafe { mem::transmute(hash) } unsafe { mem::transmute(hash) }
} }
@ -255,12 +265,20 @@ impl Ethash {
} }
impl Header { impl Header {
fn nonce(&self) -> H64 { /// Get the none field of the header.
pub fn nonce(&self) -> H64 {
decode(&self.seal()[1]) 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]) 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)] #[cfg(test)]

View File

@ -16,9 +16,7 @@
//! Interface for Evm externalities. //! Interface for Evm externalities.
use common::Bytes; use util::common::*;
use util::hash::*;
use util::uint::*;
use evm::{Schedule, Error}; use evm::{Schedule, Error};
use env_info::*; use env_info::*;

View File

@ -102,10 +102,12 @@ impl Header {
Self::default() Self::default()
} }
/// Get the number field of the header. /// Get the parent_hash field of the header.
pub fn number(&self) -> BlockNumber { self.number } pub fn parent_hash(&self) -> &H256 { &self.parent_hash }
/// Get the timestamp field of the header. /// Get the timestamp field of the header.
pub fn timestamp(&self) -> u64 { self.timestamp } 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. /// Get the author field of the header.
pub fn author(&self) -> &Address { &self.author } pub fn author(&self) -> &Address { &self.author }
@ -127,11 +129,13 @@ impl Header {
// TODO: seal_at, set_seal_at &c. // TODO: seal_at, set_seal_at &c.
/// Set the number field of the header. /// 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. /// Set the timestamp field of the header.
pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } 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. /// 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. /// 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(); } } pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } }

View File

@ -115,7 +115,7 @@ declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"}
declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"}
declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"}
declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"}
//declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"}
declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"}

View File

@ -335,10 +335,9 @@ impl fmt::Debug for State {
mod tests { mod tests {
use super::*; use super::*;
use util::hash::*; use util::common::*;
use util::trie::*; use util::trie::*;
use util::rlp::*; use util::rlp::*;
use util::uint::*;
use account::*; use account::*;
use tests::helpers::*; use tests::helpers::*;
use devtools::*; use devtools::*;

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use client::{BlockChainClient, Client, ClientConfig, BlockId}; use client::{BlockChainClient, Client, ClientConfig, BlockId};
use block::IsBlock;
use tests::helpers::*; use tests::helpers::*;
use common::*; use common::*;
use devtools::*; use devtools::*;
@ -106,3 +107,22 @@ fn can_collect_garbage() {
client.tick(); client.tick();
assert!(client.blockchain_cache_info().blocks < 100 * 1024); 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());
}

View File

@ -100,10 +100,10 @@ impl FromJson for SignedTransaction {
v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, 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) }, r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) },
s: match json.find("s") { 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") { sender: match json.find("sender") {
Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), Some(&Json::String(ref sender)) => Cell::new(Some(address_from_hex(clean(sender)))),
_ => RefCell::new(None), _ => Cell::new(None),
} }
} }
} }
@ -127,8 +127,8 @@ impl Transaction {
r: r, r: r,
s: s, s: s,
v: v + 27, v: v + 27,
hash: RefCell::new(None), hash: Cell::new(None),
sender: RefCell::new(None) sender: Cell::new(None),
} }
} }
@ -140,8 +140,8 @@ impl Transaction {
r: U256::zero(), r: U256::zero(),
s: U256::zero(), s: U256::zero(),
v: 0, v: 0,
hash: RefCell::new(None), hash: Cell::new(None),
sender: RefCell::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. /// The S field of the signature; helps describe the point on the curve.
s: U256, s: U256,
/// Cached hash. /// Cached hash.
hash: RefCell<Option<H256>>, hash: Cell<Option<H256>>,
/// Cached sender. /// Cached sender.
sender: RefCell<Option<Address>> sender: Cell<Option<Address>>,
} }
impl PartialEq for SignedTransaction { impl PartialEq for SignedTransaction {
@ -208,8 +208,8 @@ impl Decodable for SignedTransaction {
v: try!(d.val_at(6)), v: try!(d.val_at(6)),
r: try!(d.val_at(7)), r: try!(d.val_at(7)),
s: try!(d.val_at(8)), s: try!(d.val_at(8)),
hash: RefCell::new(None), hash: Cell::new(None),
sender: RefCell::new(None), sender: Cell::new(None),
}) })
} }
} }
@ -238,12 +238,13 @@ impl SignedTransaction {
/// Get the hash of this header (sha3 of the RLP). /// Get the hash of this header (sha3 of the RLP).
pub fn hash(&self) -> H256 { pub fn hash(&self) -> H256 {
let mut hash = self.hash.borrow_mut(); let hash = self.hash.get();
match &mut *hash { match hash {
&mut Some(ref h) => h.clone(), Some(h) => h,
hash @ &mut None => { None => {
*hash = Some(self.rlp_sha3()); let h = self.rlp_sha3();
hash.as_ref().unwrap().clone() self.hash.set(Some(h));
h
} }
} }
} }
@ -265,12 +266,13 @@ impl SignedTransaction {
/// Returns transaction sender. /// Returns transaction sender.
pub fn sender(&self) -> Result<Address, Error> { pub fn sender(&self) -> Result<Address, Error> {
let mut sender = self.sender.borrow_mut(); let sender = self.sender.get();
match &mut *sender { match sender {
&mut Some(ref h) => Ok(h.clone()), Some(s) => Ok(s),
sender @ &mut None => { None => {
*sender = Some(From::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3())); let s = Address::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3());
Ok(sender.as_ref().unwrap().clone()) self.sender.set(Some(s));
Ok(s)
} }
} }
} }

View File

@ -26,7 +26,7 @@ use engine::Engine;
use blockchain::*; use blockchain::*;
/// Preprocessed block data gathered in `verify_block_unordered` call /// Preprocessed block data gathered in `verify_block_unordered` call
pub struct PreVerifiedBlock { pub struct PreverifiedBlock {
/// Populated block header /// Populated block header
pub header: Header, pub header: Header,
/// Populated block transactions /// 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. /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
/// Still operates on a individual block /// Still operates on a individual block
/// Returns a PreVerifiedBlock structure populated with transactions /// Returns a PreverifiedBlock structure populated with transactions
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreVerifiedBlock, Error> { pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreverifiedBlock, Error> {
try!(engine.verify_block_unordered(&header, Some(&bytes))); try!(engine.verify_block_unordered(&header, Some(&bytes)));
for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) { for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&u, None)); 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); transactions.push(t);
} }
} }
Ok(PreVerifiedBlock { Ok(PreverifiedBlock {
header: header, header: header,
transactions: transactions, transactions: transactions,
bytes: bytes, bytes: bytes,

View File

@ -569,7 +569,7 @@ function run_installer()
if [[ $isSudo == false ]]; then if [[ $isSudo == false ]]; then
apt-get install -q -y sudo apt-get install -q -y sudo
fi 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 echo
fi fi

View File

@ -85,6 +85,10 @@ Options:
--jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. --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]. --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. -l --logging LOGGING Specify the logging level.
-v --version Show information about version. -v --version Show information about version.
-h --help Show this screen. -h --help Show this screen.
@ -114,6 +118,8 @@ struct Args {
flag_jsonrpc_cors: String, flag_jsonrpc_cors: String,
flag_logging: Option<String>, flag_logging: Option<String>,
flag_version: bool, flag_version: bool,
flag_author: String,
flag_extra_data: Option<String>,
} }
fn setup_log(init: &Option<String>) { fn setup_log(init: &Option<String>) {
@ -196,6 +202,18 @@ impl Configuration {
self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) 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 { fn _keys_path(&self) -> String {
self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap())
} }
@ -296,6 +314,8 @@ impl Configuration {
client_config.queue.max_mem_use = self.args.flag_queue_max_size; client_config.queue.max_mem_use = self.args.flag_queue_max_size;
let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap();
let client = service.client().clone(); let client = service.client().clone();
client.set_author(self.author());
client.set_extra_data(self.extra_data());
// Sync // Sync
let sync = EthSync::register(service.network(), sync_config, client); let sync = EthSync::register(service.network(), sync_config, client);
@ -354,7 +374,6 @@ impl Default for Informant {
} }
impl Informant { impl Informant {
fn format_bytes(b: usize) -> String { fn format_bytes(b: usize) -> String {
match binary_prefix(b as f64) { match binary_prefix(b as f64) {
Standalone(bytes) => format!("{} bytes", bytes), Standalone(bytes) => format!("{} bytes", bytes),

View File

@ -9,12 +9,14 @@ build = "build.rs"
[lib] [lib]
[dependencies] [dependencies]
log = "0.3"
serde = "0.7.0" serde = "0.7.0"
serde_json = "0.7.0" serde_json = "0.7.0"
jsonrpc-core = "1.2" jsonrpc-core = "1.2"
jsonrpc-http-server = "2.1" jsonrpc-http-server = "2.1"
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" } ethcore = { path = "../ethcore" }
ethash = { path = "../ethash" }
ethsync = { path = "../sync" } ethsync = { path = "../sync" }
clippy = { version = "0.0.44", optional = true } clippy = { version = "0.0.44", optional = true }
rustc-serialize = "0.3" rustc-serialize = "0.3"

View File

@ -15,14 +15,17 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Eth rpc implementation. //! Eth rpc implementation.
use std::sync::{Arc, Weak};
use ethsync::{EthSync, SyncState}; use ethsync::{EthSync, SyncState};
use jsonrpc_core::*; use jsonrpc_core::*;
use util::hash::*; use util::numbers::*;
use util::uint::*;
use util::sha3::*; use util::sha3::*;
use util::standard::{RwLock, HashMap, Arc, Weak};
use util::rlp::encode;
use ethcore::client::*; use ethcore::client::*;
use ethcore::block::{IsBlock};
use ethcore::views::*; use ethcore::views::*;
//#[macro_use] extern crate log;
use ethcore::ethereum::Ethash;
use ethcore::ethereum::denominations::shannon; use ethcore::ethereum::denominations::shannon;
use v1::traits::{Eth, EthFilter}; use v1::traits::{Eth, EthFilter};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log};
@ -30,7 +33,8 @@ use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncIn
/// Eth rpc implementation. /// Eth rpc implementation.
pub struct EthClient { pub struct EthClient {
client: Weak<Client>, client: Weak<Client>,
sync: Weak<EthSync> sync: Weak<EthSync>,
hashrates: RwLock<HashMap<H256, u64>>,
} }
impl EthClient { impl EthClient {
@ -38,7 +42,8 @@ impl EthClient {
pub fn new(client: &Arc<Client>, sync: &Arc<EthSync>) -> Self { pub fn new(client: &Arc<Client>, sync: &Arc<EthSync>) -> Self {
EthClient { EthClient {
client: Arc::downgrade(client), 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. // TODO: return real value of mining once it's implemented.
fn is_mining(&self, params: Params) -> Result<Value, Error> { fn is_mining(&self, params: Params) -> Result<Value, Error> {
match params { match params {
Params::None => Ok(Value::Bool(false)), Params::None => to_value(&!self.hashrates.read().unwrap().is_empty()),
_ => Err(Error::invalid_params()) _ => Err(Error::invalid_params())
} }
} }
@ -133,7 +138,7 @@ impl Eth for EthClient {
// TODO: return real hashrate once we have mining // TODO: return real hashrate once we have mining
fn hashrate(&self, params: Params) -> Result<Value, Error> { fn hashrate(&self, params: Params) -> Result<Value, Error> {
match params { 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()) _ => Err(Error::invalid_params())
} }
} }
@ -220,6 +225,43 @@ impl Eth for EthClient {
to_value(&logs) to_value(&logs)
}) })
} }
fn work(&self, params: Params) -> Result<Value, Error> {
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<Value, Error> {
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<Value, Error> {
// 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. /// Eth filter rpc implementation.

View File

@ -31,7 +31,7 @@ impl Web3 for Web3Client {
fn client_version(&self, params: Params) -> Result<Value, Error> { fn client_version(&self, params: Params) -> Result<Value, Error> {
match params { match params {
Params::None => { Params::None => {
Ok(Value::String(version())), Ok(Value::String(version().to_owned().replace("Parity/", "Parity//"))),
} }
_ => Err(Error::invalid_params()) _ => Err(Error::invalid_params())
} }

View File

@ -15,8 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use util::hash::*; use util::numbers::*;
use util::uint::*;
use v1::types::{Bytes, Transaction, OptionalValue}; use v1::types::{Bytes, Transaction, OptionalValue};
#[derive(Debug)] #[derive(Debug)]
@ -71,8 +70,7 @@ pub struct Block {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json; use serde_json;
use util::hash::*; use util::numbers::*;
use util::uint::*;
use v1::types::{Transaction, Bytes, OptionalValue}; use v1::types::{Transaction, Bytes, OptionalValue};
use super::*; use super::*;

View File

@ -17,7 +17,7 @@
use serde::{Deserialize, Deserializer, Error}; use serde::{Deserialize, Deserializer, Error};
use serde_json::value; use serde_json::value;
use jsonrpc_core::Value; use jsonrpc_core::Value;
use util::hash::*; use util::numbers::*;
use v1::types::BlockNumber; use v1::types::BlockNumber;
use ethcore::filter::Filter as EthFilter; use ethcore::filter::Filter as EthFilter;
use ethcore::client::BlockId; use ethcore::client::BlockId;

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::hash::*; use util::numbers::*;
use util::uint::*;
use ethcore::log_entry::LocalizedLogEntry; use ethcore::log_entry::LocalizedLogEntry;
use v1::types::Bytes; use v1::types::Bytes;
@ -55,8 +54,7 @@ impl From<LocalizedLogEntry> for Log {
mod tests { mod tests {
use serde_json; use serde_json;
use std::str::FromStr; use std::str::FromStr;
use util::hash::*; use util::numbers::*;
use util::uint::*;
use v1::types::{Bytes, Log}; use v1::types::{Bytes, Log};
#[test] #[test]

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use util::uint::*; use util::numbers::*;
#[derive(Default, Debug, Serialize, PartialEq)] #[derive(Default, Debug, Serialize, PartialEq)]
pub struct SyncInfo { pub struct SyncInfo {

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::hash::*; use util::numbers::*;
use util::uint::*;
use ethcore::transaction::{LocalizedTransaction, Action}; use ethcore::transaction::{LocalizedTransaction, Action};
use v1::types::{Bytes, OptionalValue}; use v1::types::{Bytes, OptionalValue};

View File

@ -487,19 +487,19 @@ impl ChainSync {
// TODO: Decompose block and add to self.headers and self.bodies instead // TODO: Decompose block and add to self.headers and self.bodies instead
if header.number == From::from(self.current_base_block() + 1) { if header.number == From::from(self.current_base_block() + 1) {
match io.chain().import_block(block_rlp.as_raw().to_vec()) { 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); 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); trace!(target: "sync", "New block already queued {:?}", h);
}, },
Ok(_) => { Ok(_) => {
self.last_imported_block = Some(header.number); self.last_imported_block = Some(header.number);
trace!(target: "sync", "New block queued {:?}", h); trace!(target: "sync", "New block queued {:?}", h);
}, },
Err(ImportError::UnknownParent) => { Err(Error::Block(BlockError::UnknownParent(p))) => {
unknown = true; unknown = true;
trace!(target: "sync", "New block with unknown parent {:?}", h); trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h);
}, },
Err(e) => { Err(e) => {
debug!(target: "sync", "Bad new block {:?} : {:?}", h, 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 } match self.last_imported_block { None => 0, Some(x) => x }
} }
/// Find some headers or blocks to download for a peer. fn find_block_bodies_hashes_to_request(&self, ignore_others: bool) -> (Vec<H256>, Vec<BlockNumber>) {
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 mut needed_bodies: Vec<H256> = Vec::new(); let mut needed_bodies: Vec<H256> = Vec::new();
let mut needed_numbers: Vec<BlockNumber> = Vec::new(); let mut needed_numbers: Vec<BlockNumber> = Vec::new();
@ -674,18 +665,33 @@ 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() { if !needed_bodies.is_empty() {
let (head, _) = self.headers.range_iter().next().unwrap(); let (head, _) = self.headers.range_iter().next().unwrap();
if needed_numbers.first().unwrap() - head > self.max_download_ahead_blocks as BlockNumber { 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); 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); self.request_blocks(io, peer_id, true);
return; } else {
}
self.downloading_bodies.extend(needed_numbers.iter()); self.downloading_bodies.extend(needed_numbers.iter());
replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers); replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers);
self.request_bodies(io, peer_id, needed_bodies); self.request_bodies(io, peer_id, needed_bodies);
} }
else { return;
}
// check if need to download headers // check if need to download headers
let mut start = 0; let mut start = 0;
if !self.have_common_block { if !self.have_common_block {
@ -743,7 +749,6 @@ impl ChainSync {
self.request_headers_by_number(io, peer_id, start, 1, 0, false); self.request_headers_by_number(io, peer_id, start, 1, 0, false);
} }
} }
}
/// Clear all blocks/headers marked as being downloaded by a peer. /// Clear all blocks/headers marked as being downloaded by a peer.
fn clear_peer_download(&mut self, peer_id: PeerId) { fn clear_peer_download(&mut self, peer_id: PeerId) {
@ -791,12 +796,12 @@ impl ChainSync {
} }
match io.chain().import_block(block_rlp.out()) { match io.chain().import_block(block_rlp.out()) {
Err(ImportError::AlreadyInChain) => { Err(Error::Import(ImportError::AlreadyInChain)) => {
trace!(target: "sync", "Block already in chain {:?}", h); trace!(target: "sync", "Block already in chain {:?}", h);
self.last_imported_block = Some(headers.0 + i as BlockNumber); self.last_imported_block = Some(headers.0 + i as BlockNumber);
self.last_imported_hash = Some(h.clone()); self.last_imported_hash = Some(h.clone());
}, },
Err(ImportError::AlreadyQueued) => { Err(Error::Import(ImportError::AlreadyQueued)) => {
trace!(target: "sync", "Block already queued {:?}", h); trace!(target: "sync", "Block already queued {:?}", h);
self.last_imported_block = Some(headers.0 + i as BlockNumber); self.last_imported_block = Some(headers.0 + i as BlockNumber);
self.last_imported_hash = Some(h.clone()); self.last_imported_hash = Some(h.clone());
@ -1189,8 +1194,8 @@ impl ChainSync {
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
/// propagades latest block to lagging peers /// propagates latest block to lagging peers
fn propagade_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { fn propagate_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize {
let updated_peers = { let updated_peers = {
let lagging_peers = self.get_lagging_peers(io); let lagging_peers = self.get_lagging_peers(io);
@ -1216,8 +1221,8 @@ impl ChainSync {
sent sent
} }
/// propagades new known hashes to all peers /// propagates new known hashes to all peers
fn propagade_new_hashes(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { 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 updated_peers = self.get_lagging_peers(io);
let mut sent = 0; let mut sent = 0;
let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(local_best.clone())).unwrap()).parent_hash(); let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(local_best.clone())).unwrap()).parent_hash();
@ -1252,8 +1257,8 @@ impl ChainSync {
pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) { pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) {
let chain = io.chain().chain_info(); 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 { 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 blocks = self.propagate_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 hashes = self.propagate_new_hashes(&chain.best_block_hash, chain.best_block_number, io);
if blocks != 0 || hashes != 0 { if blocks != 0 || hashes != 0 {
trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
} }
@ -1277,7 +1282,8 @@ impl ChainSync {
good.for_each(|txs| { good.for_each(|txs| {
let mut transaction_queue = self.transaction_queue.lock().unwrap(); let mut transaction_queue = self.transaction_queue.lock().unwrap();
transaction_queue.remove_all(&txs); let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
transaction_queue.remove_all(&hashes);
}); });
bad.for_each(|txs| { bad.for_each(|txs| {
// populate sender // populate sender
@ -1465,7 +1471,7 @@ mod tests {
let best_number = client.chain_info().best_block_number; let best_number = client.chain_info().best_block_number;
let mut io = TestIo::new(&mut client, &mut queue, None); 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 // 1 message should be send
assert_eq!(1, io.queue.len()); assert_eq!(1, io.queue.len());
@ -1485,7 +1491,7 @@ mod tests {
let best_number = client.chain_info().best_block_number; let best_number = client.chain_info().best_block_number;
let mut io = TestIo::new(&mut client, &mut queue, None); 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 // 1 message should be send
assert_eq!(1, io.queue.len()); assert_eq!(1, io.queue.len());
@ -1591,7 +1597,7 @@ mod tests {
let best_number = client.chain_info().best_block_number; let best_number = client.chain_info().best_block_number;
let mut io = TestIo::new(&mut client, &mut queue, None); 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 data = &io.queue[0].data.clone();
let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(&data)); 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 best_number = client.chain_info().best_block_number;
let mut io = TestIo::new(&mut client, &mut queue, None); 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 data = &io.queue[0].data.clone();
let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data));

View File

@ -122,7 +122,7 @@ fn status_packet() {
} }
#[test] #[test]
fn propagade_hashes() { fn propagate_hashes() {
let mut net = TestNet::new(6); let mut net = TestNet::new(6);
net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle);
net.sync(); net.sync();
@ -148,7 +148,7 @@ fn propagade_hashes() {
} }
#[test] #[test]
fn propagade_blocks() { fn propagate_blocks() {
let mut net = TestNet::new(2); let mut net = TestNet::new(2);
net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle); net.peer_mut(1).chain.add_blocks(10, BlocksWith::Uncle);
net.sync(); net.sync();

View File

@ -18,121 +18,126 @@
//! Transaction Queue //! Transaction Queue
use std::vec::Vec;
use std::cmp::{Ordering}; use std::cmp::{Ordering};
use std::collections::{HashMap, BTreeSet}; use std::collections::{HashMap, BTreeSet};
use util::uint::{Uint, U256}; use util::numbers::{Uint, U256};
use util::hash::{Address}; use util::hash::{Address, H256};
use util::table::*; use util::table::*;
use ethcore::transaction::*; use ethcore::transaction::*;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct VerifiedTransaction { struct TransactionOrder {
tx: SignedTransaction, nonce_height: U256,
nonce_height: U256 gas_price: U256,
hash: H256,
} }
impl VerifiedTransaction { impl TransactionOrder {
pub fn new(tx: SignedTransaction, nonce_height: U256) -> VerifiedTransaction { pub fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self {
VerifiedTransaction { TransactionOrder {
tx: tx, nonce_height: tx.nonce() - base_nonce,
nonce_height: nonce_height gas_price: tx.transaction.gas_price,
hash: tx.hash(),
} }
} }
pub fn sender(&self) -> Address {
self.tx.sender().unwrap()
}
} }
impl Eq for VerifiedTransaction {} impl Eq for TransactionOrder {}
impl PartialEq for VerifiedTransaction { impl PartialEq for TransactionOrder {
fn eq(&self, other: &VerifiedTransaction) -> bool { fn eq(&self, other: &TransactionOrder) -> bool {
self.cmp(other) == Ordering::Equal self.cmp(other) == Ordering::Equal
} }
} }
impl PartialOrd for VerifiedTransaction { impl PartialOrd for TransactionOrder {
fn partial_cmp(&self, other: &VerifiedTransaction) -> Option<Ordering> { fn partial_cmp(&self, other: &TransactionOrder) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl Ord for VerifiedTransaction { impl Ord for TransactionOrder {
fn cmp(&self, b: &VerifiedTransaction) -> Ordering { fn cmp(&self, b: &TransactionOrder) -> Ordering {
// First check nonce_height // First check nonce_height
if self.nonce_height != b.nonce_height { if self.nonce_height != b.nonce_height {
return self.nonce_height.cmp(&b.nonce_height); return self.nonce_height.cmp(&b.nonce_height);
} }
// Then compare gas_prices // Then compare gas_prices
let a_gas = self.tx.gas_price; let a_gas = self.gas_price;
let b_gas = b.tx.gas_price; let b_gas = b.gas_price;
if a_gas != b_gas { if a_gas != b_gas {
return a_gas.cmp(&b_gas); return a_gas.cmp(&b_gas);
} }
// Compare nonce // Compare hashes
let a_nonce = self.tx.nonce; self.hash.cmp(&b.hash)
let b_nonce = b.tx.nonce;
if a_nonce != b_nonce {
return a_nonce.cmp(&b_nonce);
}
// and senders
let a_sender = self.sender();
let b_sender = b.sender();
a_sender.cmp(&b_sender)
} }
} }
struct TransactionsByPriorityAndAddress { struct VerifiedTransaction {
priority: BTreeSet<VerifiedTransaction>, transaction: SignedTransaction
address: Table<Address, U256, VerifiedTransaction>, }
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<TransactionOrder>,
by_address: Table<Address, U256, TransactionOrder>,
limit: usize, limit: usize,
} }
impl TransactionsByPriorityAndAddress { impl TransactionSet {
fn insert(&mut self, address: Address, nonce: U256, verified_tx: VerifiedTransaction) { fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) {
self.priority.insert(verified_tx.clone()); self.by_priority.insert(order.clone());
self.address.insert(address, nonce, verified_tx); self.by_address.insert(sender, nonce, order);
} }
fn enforce_limit(&mut self) { fn enforce_limit(&mut self, by_hash: &HashMap<H256, VerifiedTransaction>) {
let len = self.priority.len(); let len = self.by_priority.len();
if len <= self.limit { if len <= self.limit {
return; return;
} }
let to_remove : Vec<SignedTransaction> = { let to_drop : Vec<&VerifiedTransaction> = {
self.priority self.by_priority
.iter() .iter()
.skip(self.limit) .skip(self.limit)
.map(|v_tx| v_tx.tx.clone()) .map(|order| by_hash.get(&order.hash).expect("Inconsistency in queue detected."))
.collect() .collect()
}; };
for tx in to_remove { for tx in to_drop {
self.remove(&tx); self.drop(&tx.sender(), &tx.nonce());
} }
} }
fn remove_by_address(&mut self, sender: &Address, nonce: &U256) -> Option<VerifiedTransaction> { fn drop(&mut self, sender: &Address, nonce: &U256) -> Option<TransactionOrder> {
if let Some(verified_tx) = self.address.remove(sender, nonce) { if let Some(tx_order) = self.by_address.remove(sender, nonce) {
self.priority.remove(&verified_tx); self.by_priority.remove(&tx_order);
return Some(verified_tx); return Some(tx_order);
} }
None None
} }
fn remove(&mut self, tx: &SignedTransaction) -> Option<VerifiedTransaction> {
// First find the transaction by address
let address = tx.sender().unwrap();
self.remove_by_address(&address, &tx.nonce)
}
fn clear(&mut self) { fn clear(&mut self) {
self.priority.clear(); self.by_priority.clear();
self.address.clear(); self.by_address.clear();
} }
} }
@ -148,9 +153,11 @@ pub struct TransactionQueueStatus {
/// TransactionQueue implementation /// TransactionQueue implementation
pub struct TransactionQueue { pub struct TransactionQueue {
/// Priority queue for transactions that can go to block /// 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 /// 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<H256, VerifiedTransaction>,
/// Last nonce of transaction in current /// Last nonce of transaction in current
last_nonces: HashMap<Address, U256>, last_nonces: HashMap<Address, U256>,
/// First nonce of transaction in current (used to determine priority) /// 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 /// Create new instance of this Queue with specified limits
pub fn with_limits(current_limit: usize, future_limit: usize) -> Self { pub fn with_limits(current_limit: usize, future_limit: usize) -> Self {
let current = TransactionsByPriorityAndAddress { let current = TransactionSet {
address: Table::new(), by_priority: BTreeSet::new(),
priority: BTreeSet::new(), by_address: Table::new(),
limit: current_limit, limit: current_limit,
}; };
let future = TransactionsByPriorityAndAddress { let future = TransactionSet {
address: Table::new(), by_priority: BTreeSet::new(),
priority: BTreeSet::new(), by_address: Table::new(),
limit: future_limit, limit: future_limit,
}; };
TransactionQueue { TransactionQueue {
current: current, current: current,
future: future, future: future,
by_hash: HashMap::new(),
last_nonces: HashMap::new(), last_nonces: HashMap::new(),
first_nonces: HashMap::new(), first_nonces: HashMap::new(),
} }
@ -187,8 +195,8 @@ impl TransactionQueue {
/// Returns current status for this queue /// Returns current status for this queue
pub fn status(&self) -> TransactionQueueStatus { pub fn status(&self) -> TransactionQueueStatus {
TransactionQueueStatus { TransactionQueueStatus {
pending: self.current.priority.len(), pending: self.current.by_priority.len(),
future: self.future.priority.len(), future: self.future.by_priority.len(),
} }
} }
@ -203,29 +211,42 @@ impl TransactionQueue {
/// Add signed transaction to queue to be verified and imported /// Add signed transaction to queue to be verified and imported
pub fn add<T>(&mut self, tx: SignedTransaction, fetch_nonce: &T) pub fn add<T>(&mut self, tx: SignedTransaction, fetch_nonce: &T)
where T: Fn(&Address) -> U256 { 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 /// If gap is introduced marks subsequent transactions as future
pub fn remove_all(&mut self, txs: &[SignedTransaction]) { pub fn remove_all(&mut self, transaction_hashes: &[H256]) {
for tx in txs { for transaction_hash in transaction_hashes {
self.remove(&tx); self.remove(&transaction_hash);
} }
} }
/// Removes transaction from queue. /// Removes transaction identified by hashes from queue.
/// ///
/// If gap is introduced marks subsequent transactions as future /// 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 // Remove from current
let removed = self.current.remove(tx); let order = self.current.drop(&sender, &nonce);
if let Some(verified_tx) = removed { if order.is_none() {
let sender = verified_tx.sender(); return;
}
// Are there any other transactions from this sender? // Are there any other transactions from this sender?
if !self.current.address.has_row(&sender) { if !self.current.by_address.has_row(&sender) {
// Clear last & first nonces // Clear last & first nonces
self.last_nonces.remove(&sender); self.last_nonces.remove(&sender);
self.first_nonces.remove(&sender); self.first_nonces.remove(&sender);
@ -234,20 +255,19 @@ impl TransactionQueue {
// Let's find those with higher nonce (TODO [todr] optimize?) // Let's find those with higher nonce (TODO [todr] optimize?)
let to_move_to_future = { let to_move_to_future = {
let row_map = self.current.address.row(&sender).unwrap(); let row_map = self.current.by_address.row(&sender).unwrap();
let tx_nonce = verified_tx.tx.nonce;
let mut to_future = Vec::new(); let mut to_future = Vec::new();
let mut highest = U256::zero(); let mut highest = U256::zero();
let mut lowest = tx_nonce.clone(); let mut lowest = nonce.clone();
// Search nonces to remove and track lowest and highest // Search nonces to remove and track lowest and highest
for (nonce, _) in row_map.iter() { for (current_nonce, _) in row_map.iter() {
if nonce > &tx_nonce { if current_nonce > &nonce {
to_future.push(nonce.clone()); to_future.push(current_nonce.clone());
} else if nonce > &highest { } else if current_nonce > &highest {
highest = nonce.clone(); highest = current_nonce.clone();
} else if nonce < &lowest { } else if current_nonce < &lowest {
lowest = nonce.clone(); lowest = current_nonce.clone();
} }
} }
@ -258,7 +278,7 @@ impl TransactionQueue {
self.last_nonces.insert(sender.clone(), highest); self.last_nonces.insert(sender.clone(), highest);
} }
if lowest == tx_nonce { if lowest == nonce {
self.first_nonces.remove(&sender); self.first_nonces.remove(&sender);
} else { } else {
self.first_nonces.insert(sender.clone(), lowest); self.first_nonces.insert(sender.clone(), lowest);
@ -269,35 +289,29 @@ impl TransactionQueue {
}; };
for k in to_move_to_future { for k in to_move_to_future {
if let Some(v) = self.current.remove_by_address(&sender, &k) { if let Some(v) = self.current.drop(&sender, &k) {
self.future.insert(sender.clone(), v.tx.nonce, v); // TODO [todr] Recalculate height?
} self.future.insert(sender.clone(), k, v);
}
self.future.enforce_limit();
return;
}
// Remove from future
{
let sender = tx.sender().unwrap();
if let Some(_) = self.future.remove_by_address(&sender, &tx.nonce) {
return;
} }
} }
self.future.enforce_limit(&self.by_hash);
} }
/// Returns top transactions from the queue /// Returns top transactions from the queue
pub fn top_transactions(&self, size: usize) -> Vec<SignedTransaction> { pub fn top_transactions(&self, size: usize) -> Vec<SignedTransaction> {
self.current.priority self.current.by_priority
.iter() .iter()
.take(size) .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 /// Removes all elements (in any state) from the queue
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.current.clear(); self.current.clear();
self.future.clear(); self.future.clear();
self.by_hash.clear();
self.last_nonces.clear(); self.last_nonces.clear();
self.first_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<U256> { fn move_future_txs(&mut self, address: Address, current_nonce: U256, first_nonce: U256) -> Option<U256> {
let mut current_nonce = current_nonce + U256::one(); let mut current_nonce = current_nonce + U256::one();
{ {
let txs_by_nonce = self.future.address.row_mut(&address); let by_nonce = self.future.by_address.row_mut(&address);
if let None = txs_by_nonce { if let None = by_nonce {
return None; return None;
} }
let mut txs_by_nonce = txs_by_nonce.unwrap(); let mut by_nonce = by_nonce.unwrap();
while let Some(order) = by_nonce.remove(&current_nonce) {
while let Some(tx) = txs_by_nonce.remove(&current_nonce) { // remove also from priority and hash
// remove also from priority self.future.by_priority.remove(&order);
self.future.priority.remove(&tx);
// Put to current // Put to current
let height = current_nonce - first_nonce; let transaction = self.by_hash.get(&order.hash).expect("TransactionQueue Inconsistency");
let verified_tx = VerifiedTransaction::new(tx.tx, U256::from(height)); let order = TransactionOrder::for_transaction(transaction, first_nonce);
self.current.insert(address.clone(), verified_tx.tx.nonce, verified_tx); self.current.insert(address.clone(), transaction.nonce(), order);
current_nonce = current_nonce + U256::one(); 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 // Returns last inserted nonce
Some(current_nonce - U256::one()) Some(current_nonce - U256::one())
} }
fn import_tx<T>(&mut self, tx: SignedTransaction, fetch_nonce: &T) fn import_tx<T>(&mut self, tx: VerifiedTransaction, fetch_nonce: &T)
where T: Fn(&Address) -> U256 { where T: Fn(&Address) -> U256 {
let nonce = tx.nonce; let nonce = tx.nonce();
let address = tx.sender().unwrap(); let address = tx.sender();
let next_nonce = U256::one() + self.last_nonces let next_nonce = U256::one() + self.last_nonces
.get(&address) .get(&address)
@ -338,11 +351,12 @@ impl TransactionQueue {
// Check height // Check height
if nonce > next_nonce { if nonce > next_nonce {
let height = nonce - next_nonce; let order = TransactionOrder::for_transaction(&tx, next_nonce);
let verified_tx = VerifiedTransaction::new(tx, height); // Insert to by_hash
self.by_hash.insert(tx.hash(), tx);
// We have a gap - put to future // We have a gap - put to future
self.future.insert(address, nonce, verified_tx); self.future.insert(address, nonce, order);
self.future.enforce_limit(); self.future.enforce_limit(&self.by_hash);
return; return;
} else if next_nonce > nonce { } else if next_nonce > nonce {
// Droping transaction // Droping transaction
@ -355,29 +369,34 @@ impl TransactionQueue {
.cloned() .cloned()
.unwrap_or_else(|| nonce.clone()); .unwrap_or_else(|| nonce.clone());
let height = nonce - first_nonce; let order = TransactionOrder::for_transaction(&tx, first_nonce);
let verified_tx = VerifiedTransaction::new(tx, height); // Insert to by_hash
self.by_hash.insert(tx.hash(), tx);
// Insert to current // 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? // But maybe there are some more items waiting in future?
let new_last_nonce = self.move_future_txs(address.clone(), nonce, first_nonce); let new_last_nonce = self.move_future_txs(address.clone(), nonce, first_nonce);
self.first_nonces.insert(address.clone(), first_nonce); self.first_nonces.insert(address.clone(), first_nonce);
self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce)); self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce));
// Enforce limit // Enforce limit
self.current.enforce_limit(); self.current.enforce_limit(&self.by_hash);
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
extern crate rustc_serialize; extern crate rustc_serialize;
use self::rustc_serialize::hex::FromHex; use self::rustc_serialize::hex::FromHex;
use std::collections::{HashMap, BTreeSet};
use util::crypto::KeyPair; use util::crypto::KeyPair;
use util::uint::{U256, Uint}; use util::numbers::{U256, Uint};
use util::hash::{Address}; use util::hash::{Address};
use util::table::*;
use ethcore::transaction::*; use ethcore::transaction::*;
use super::*; use super::*;
use super::{TransactionSet, TransactionOrder, VerifiedTransaction};
fn new_unsigned_tx(nonce: U256) -> Transaction { fn new_unsigned_tx(nonce: U256) -> Transaction {
Transaction { Transaction {
@ -409,6 +428,46 @@ mod test {
(tx.sign(secret), tx2.sign(secret)) (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] #[test]
fn should_import_tx() { fn should_import_tx() {
// given // given
@ -496,8 +555,8 @@ mod test {
assert_eq!(txq2.status().future, 1); assert_eq!(txq2.status().future, 1);
// when // when
txq2.remove(&tx); txq2.remove(&tx.hash());
txq2.remove(&tx2); txq2.remove(&tx2.hash());
// then // then
@ -519,7 +578,7 @@ mod test {
assert_eq!(txq.status().pending, 3); assert_eq!(txq.status().pending, 3);
// when // when
txq.remove(&tx); txq.remove(&tx.hash());
// then // then
let stats = txq.status(); let stats = txq.status();
@ -609,14 +668,15 @@ mod test {
assert_eq!(txq.status().pending, 2); assert_eq!(txq.status().pending, 2);
// when // when
txq.remove(&tx1); txq.remove(&tx1.hash());
assert_eq!(txq.status().pending, 0);
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
txq.add(tx1.clone(), &default_nonce); txq.add(tx1.clone(), &default_nonce);
// then // then
let stats = txq.status(); let stats = txq.status();
assert_eq!(stats.pending, 2);
assert_eq!(stats.future, 0); assert_eq!(stats.future, 0);
assert_eq!(stats.pending, 2);
} }

View File

@ -35,6 +35,7 @@ ethcore-devtools = { path = "../devtools" }
libc = "0.2.7" libc = "0.2.7"
vergen = "0.1" vergen = "0.1"
target_info = "0.1" target_info = "0.1"
bigint = { path = "bigint" }
[features] [features]
default = [] default = []

23
util/bigint/Cargo.toml Normal file
View File

@ -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 <admin@ethcore.io>"]
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=[]

25
util/bigint/build.rs Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
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");
}
}

23
util/bigint/src/lib.rs Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#![cfg_attr(asm_available, feature(asm))]
extern crate rustc_serialize;
extern crate serde;
#[macro_use] extern crate heapsize;
pub mod uint;

View File

@ -36,10 +36,19 @@
//! The functions here are designed to be fast. //! The functions here are designed to be fast.
//! //!
use standard::*; use std::fmt;
use from_json::*; use std::cmp;
use rustc_serialize::hex::ToHex;
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 serde;
use rustc_serialize::hex::{FromHex, FromHexError, ToHex};
macro_rules! impl_map_from { macro_rules! impl_map_from {
($thing:ident, $from:ty, $to:ty) => { ($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 { macro_rules! uint_overflowing_add {
($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({
uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) uint_overflowing_add_reg!($name, $n_words, $self_expr, $other)
@ -88,8 +97,7 @@ macro_rules! uint_overflowing_add_reg {
}) })
} }
#[cfg(all(asm_available, target_arch="x86_64"))]
#[cfg(all(x64asm, target_arch="x86_64"))]
macro_rules! uint_overflowing_add { macro_rules! uint_overflowing_add {
(U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({
let mut result: [u64; 4] = unsafe { mem::uninitialized() }; 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 { macro_rules! uint_overflowing_sub {
($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({
let res = overflowing!((!$other).overflowing_add(From::from(1u64))); 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 { macro_rules! uint_overflowing_sub {
(U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({
let mut result: [u64; 4] = unsafe { mem::uninitialized() }; 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 { macro_rules! uint_overflowing_mul {
(U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({
let mut result: [u64; 4] = unsafe { mem::uninitialized() }; 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 { macro_rules! uint_overflowing_mul {
($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({
uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) 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) => ({ ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({
let mut res = $name::from(0u64); let mut res = $name::from(0u64);
let mut overflow = false; let mut overflow = false;
// TODO: be more efficient about this
for i in 0..(2 * $n_words) { for i in 0..(2 * $n_words) {
let v = overflowing!($self_expr.overflowing_mul_u32(($other >> (32 * i)).low_u32()), overflow); 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); 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. /// Large, fixed-length unsigned integer type.
pub trait Uint: Sized + Default + FromStr + From<u64> + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { pub trait Uint: Sized + Default + FromStr + From<u64> + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash {
/// Returns new instance equalling zero. /// Returns new instance equalling zero.
fn zero() -> Self; 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, u8, u64);
impl_map_from!($name, u16, u64); impl_map_from!($name, u16, u64);
@ -1100,7 +1091,7 @@ construct_uint!(U128, 2);
impl U256 { impl U256 {
/// Multiplies two 256-bit integers to produce full 512-bit integer /// Multiplies two 256-bit integers to produce full 512-bit integer
/// No overflow possible /// 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 { pub fn full_mul(self, other: U256) -> U512 {
let self_t: &[u64; 4] = unsafe { &mem::transmute(self) }; let self_t: &[u64; 4] = unsafe { &mem::transmute(self) };
let other_t: &[u64; 4] = unsafe { &mem::transmute(other) }; 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 /// Multiplies two 256-bit integers to produce full 512-bit integer
/// No overflow possible /// 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 { pub fn full_mul(self, other: U256) -> U512 {
let self_512 = U512::from(self); let self_512 = U512::from(self);
let other_512 = U512::from(other); let other_512 = U512::from(other);
@ -1275,6 +1266,33 @@ impl From<U512> 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<U256> for U128 { impl From<U256> for U128 {
fn from(value: U256) -> U128 { fn from(value: U256) -> U128 {
let U256(ref arr) = value; 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. /// 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]); pub const ONE_U256: U256 = U256([0x01u64, 0x00u64, 0x00u64, 0x00u64]);
known_heap_size!(0, U128, U256);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use uint::{Uint, U128, U256, U512}; use uint::{Uint, U128, U256, U512};
@ -1982,6 +2003,7 @@ mod tests {
#[test] #[test]
#[cfg_attr(feature = "dev", allow(cyclomatic_complexity))]
fn u256_multi_full_mul() { fn u256_multi_full_mul() {
let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0])); 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); assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result);

View File

@ -1,13 +1,7 @@
extern crate vergen; extern crate vergen;
extern crate rustc_version;
use vergen::*; use vergen::*;
use rustc_version::{version_meta, Channel};
fn main() { fn main() {
vergen(OutputFns::all()).unwrap(); vergen(OutputFns::all()).unwrap();
if let Channel::Nightly = version_meta().channel {
println!("cargo:rustc-cfg=x64asm");
}
} }

View File

@ -19,10 +19,9 @@
pub use standard::*; pub use standard::*;
pub use from_json::*; pub use from_json::*;
pub use error::*; pub use error::*;
pub use hash::*;
pub use uint::*;
pub use bytes::*; pub use bytes::*;
pub use vector::*; pub use vector::*;
pub use numbers::*;
pub use sha3::*; pub use sha3::*;
#[macro_export] #[macro_export]

View File

@ -16,9 +16,8 @@
//! Ethcore crypto. //! Ethcore crypto.
use hash::*; use numbers::*;
use bytes::*; use bytes::*;
use uint::*;
use secp256k1::{key, Secp256k1}; use secp256k1::{key, Secp256k1};
use rand::os::OsRng; use rand::os::OsRng;
@ -151,8 +150,7 @@ impl KeyPair {
/// EC functions /// EC functions
pub mod ec { pub mod ec {
use hash::*; use numbers::*;
use uint::*;
use standard::*; use standard::*;
use crypto::*; use crypto::*;
use crypto::{self}; use crypto::{self};

View File

@ -17,6 +17,7 @@
//! Coversion from json. //! Coversion from json.
use standard::*; use standard::*;
use bigint::uint::*;
#[macro_export] #[macro_export]
macro_rules! xjson { macro_rules! xjson {
@ -30,3 +31,20 @@ pub trait FromJson {
/// Convert a JSON value to an instance of this type. /// Convert a JSON value to an instance of this type.
fn from_json(json: &Json) -> Self; 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(),
}
}
}

View File

@ -23,7 +23,7 @@ use rand::Rng;
use rand::os::OsRng; use rand::os::OsRng;
use bytes::{BytesConvertable,Populatable}; use bytes::{BytesConvertable,Populatable};
use from_json::*; use from_json::*;
use uint::{Uint, U256}; use bigint::uint::{Uint, U256};
use rustc_serialize::hex::ToHex; use rustc_serialize::hex::ToHex;
use serde; 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 { impl Clone for $from {
fn clone(&self) -> $from { fn clone(&self) -> $from {
unsafe { unsafe {
@ -595,7 +597,7 @@ pub fn h256_from_hex(s: &str) -> H256 {
/// Convert `n` to an `H256`, setting the rightmost 8 bytes. /// Convert `n` to an `H256`, setting the rightmost 8 bytes.
pub fn h256_from_u64(n: u64) -> H256 { pub fn h256_from_u64(n: u64) -> H256 {
use uint::U256; use bigint::uint::U256;
H256::from(&U256::from(n)) H256::from(&U256::from(n))
} }
@ -631,7 +633,7 @@ pub static ZERO_H256: H256 = H256([0x00; 32]);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hash::*; use hash::*;
use uint::*; use bigint::uint::*;
use std::str::FromStr; use std::str::FromStr;
#[test] #[test]

View File

@ -16,8 +16,7 @@
//! Calculates heapsize of util types. //! Calculates heapsize of util types.
use uint::*;
use hash::*; use hash::*;
known_heap_size!(0, H32, H64, H128, Address, H256, H264, H512, H520, H1024, H2048); known_heap_size!(0, H32, H64, H128, Address, H256, H264, H512, H520, H1024, H2048);
known_heap_size!(0, U128, U256);

View File

@ -121,6 +121,7 @@ impl JournalDB {
// and the key is safe to delete. // and the key is safe to delete.
// record new commit's details. // record new commit's details.
debug!("commit: #{} ({}), end era: {:?}", now, id, end);
let batch = DBTransaction::new(); let batch = DBTransaction::new();
let mut counters = self.counters.write().unwrap(); let mut counters = self.counters.write().unwrap();
{ {
@ -167,15 +168,18 @@ impl JournalDB {
&last &last
})) { })) {
let rlp = Rlp::new(&rlp_data); let rlp = Rlp::new(&rlp_data);
let inserts: Vec<H256> = rlp.val_at(1); let mut inserts: Vec<H256> = rlp.val_at(1);
JournalDB::decrease_counters(&inserts, &mut counters); JournalDB::decrease_counters(&inserts, &mut counters);
// Collect keys to be removed. These are removed keys for canonical block, inserted for non-canonical // Collect keys to be removed. These are removed keys for canonical block, inserted for non-canonical
if canon_id == rlp.val_at(0) { if canon_id == rlp.val_at(0) {
to_remove.extend(rlp.at(2).iter().map(|r| r.as_val::<H256>())); let mut canon_deletes: Vec<H256> = rlp.val_at(2);
trace!("Purging nodes deleted from canon: {:?}", canon_deletes);
to_remove.append(&mut canon_deletes);
canon_inserts = inserts; canon_inserts = inserts;
} }
else { else {
to_remove.extend(inserts); trace!("Purging nodes inserted in non-canon: {:?}", inserts);
to_remove.append(&mut inserts);
} }
try!(batch.delete(&last)); try!(batch.delete(&last));
index += 1; index += 1;
@ -188,7 +192,7 @@ impl JournalDB {
try!(batch.delete(&h)); try!(batch.delete(&h));
deletes += 1; 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 // Commit overlay insertions
@ -209,7 +213,7 @@ impl JournalDB {
} }
try!(self.backing.write(batch)); try!(self.backing.write(batch));
trace!("JournalDB::commit() deleted {} nodes", deletes); debug!("commit: Deleted {} nodes", deletes);
Ok(ret) Ok(ret)
} }
@ -258,7 +262,7 @@ impl JournalDB {
era -= 1; era -= 1;
} }
} }
trace!("Recovered {} counters", res.len()); debug!("Recovered {} counters", res.len());
res res
} }
} }

View File

@ -99,10 +99,20 @@ mod tests {
use common::*; use common::*;
use keys::store::SecretStore; 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] #[test]
fn can_enumerate() { 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()); assert_eq!(2, keys.len());
} }
@ -110,7 +120,7 @@ mod tests {
fn can_import() { fn can_import() {
let temp = ::devtools::RandomTempPath::create_dir(); let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path()); 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()); let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap());
assert!(key.is_some()); assert!(key.is_some());
} }
@ -119,7 +129,7 @@ mod tests {
fn can_import_directory() { fn can_import_directory() {
let temp = ::devtools::RandomTempPath::create_dir(); let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path()); 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()); let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap());
assert!(key.is_some()); assert!(key.is_some());
@ -134,7 +144,7 @@ mod tests {
let temp = ::devtools::RandomTempPath::create_dir(); let temp = ::devtools::RandomTempPath::create_dir();
{ {
let mut secret_store = SecretStore::new_in(temp.as_path()); 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()); let key_directory = KeyDirectory::new(&temp.as_path());
@ -156,7 +166,7 @@ mod tests {
let temp = ::devtools::RandomTempPath::create_dir(); let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path()); 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::<Bytes>(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap(), "123"); let val = secret_store.get::<Bytes>(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap(), "123");
assert!(val.is_ok()); assert!(val.is_ok());

View File

@ -16,7 +16,6 @@
#![warn(missing_docs)] #![warn(missing_docs)]
#![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", feature(plugin))]
#![cfg_attr(x64asm, feature(asm))]
#![cfg_attr(feature="dev", plugin(clippy))] #![cfg_attr(feature="dev", plugin(clippy))]
// Clippy settings // Clippy settings
@ -111,15 +110,16 @@ extern crate libc;
extern crate rustc_version; extern crate rustc_version;
extern crate target_info; extern crate target_info;
extern crate vergen; extern crate vergen;
extern crate bigint;
pub mod standard; pub mod standard;
#[macro_use] #[macro_use]
pub mod from_json; pub mod from_json;
#[macro_use] #[macro_use]
pub mod common; pub mod common;
pub mod numbers;
pub mod error; pub mod error;
pub mod hash; pub mod hash;
pub mod uint;
pub mod bytes; pub mod bytes;
pub mod rlp; pub mod rlp;
pub mod misc; pub mod misc;

View File

@ -18,6 +18,7 @@
use std::fs::File; use std::fs::File;
use common::*; use common::*;
use rlp::{Stream, RlpStream};
use target_info::Target; use target_info::Target;
use rustc_version; use rustc_version;
@ -69,5 +70,19 @@ pub fn contents(name: &str) -> Result<Bytes, UtilError> {
/// Get the standard version string for this software. /// Get the standard version string for this software.
pub fn version() -> String { 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()
} }

20
util/src/numbers.rs Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
//! Utils number types.
pub use hash::*;
pub use bigint::uint::*;

View File

@ -21,7 +21,7 @@ use std::mem;
use std::fmt; use std::fmt;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::error::Error as StdError; use std::error::Error as StdError;
use uint::{Uint, U128, U256}; use bigint::uint::{Uint, U128, U256};
use hash::FixedHash; use hash::FixedHash;
use elastic_array::*; use elastic_array::*;

View File

@ -21,7 +21,7 @@ use std::{fmt, cmp};
use std::str::FromStr; use std::str::FromStr;
use rlp; use rlp;
use rlp::{UntrustedRlp, RlpStream, View, Stream, DecoderError}; use rlp::{UntrustedRlp, RlpStream, View, Stream, DecoderError};
use uint::U256; use bigint::uint::U256;
#[test] #[test]
fn rlp_at() { fn rlp_at() {

View File

@ -111,7 +111,7 @@ impl<Row, Col, Val> Table<Row, Col, Val>
/// ///
/// Returns previous value (if any) /// Returns previous value (if any)
pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option<Val> { pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option<Val> {
self.map.entry(row).or_insert_with(|| HashMap::new()).insert(col, val) self.map.entry(row).or_insert_with(HashMap::new).insert(col, val)
} }
} }