diff --git a/.travis.yml b/.travis.yml
index 8d2349dae..7213b8f09 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,6 +13,8 @@ matrix:
allow_failures:
- rust: nightly
include:
+ - rust: stable
+ env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
- rust: beta
env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
- rust: nightly
@@ -52,7 +54,7 @@ after_success: |
./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* &&
[ $TRAVIS_BRANCH = master ] &&
[ $TRAVIS_PULL_REQUEST = false ] &&
- [ $TRAVIS_RUST_VERSION = beta ] &&
+ [ $TRAVIS_RUST_VERSION = stable ] &&
cargo doc --no-deps --verbose ${KCOV_FEATURES} ${TARGETS} &&
echo '' > target/doc/index.html &&
pip install --user ghp-import &&
diff --git a/Cargo.lock b/Cargo.lock
index 9ce1c4372..55ed996ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -81,6 +81,15 @@ name = "cfg-if"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "chrono"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "clippy"
version = "0.0.44"
@@ -215,16 +224,19 @@ name = "ethcore-rpc"
version = "0.9.99"
dependencies = [
"clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ethash 0.9.99",
"ethcore 0.9.99",
"ethcore-util 0.9.99",
"ethsync 0.9.99",
"jsonrpc-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-http-server 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -233,6 +245,7 @@ version = "0.9.99"
dependencies = [
"arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"bigint 0.1.0",
+ "chrono 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -272,6 +285,7 @@ dependencies = [
"heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -819,6 +833,14 @@ name = "traitobject"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "transient-hashmap"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "typeable"
version = "0.1.2"
diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs
index 6c311993b..eb64151d0 100644
--- a/ethash/src/compute.rs
+++ b/ethash/src/compute.rs
@@ -172,7 +172,8 @@ fn get_data_size(block_number: u64) -> usize {
}
#[inline]
-fn get_seedhash(block_number: u64) -> H256 {
+/// Given the `block_number`, determine the seed hash for Ethash.
+pub fn get_seedhash(block_number: u64) -> H256 {
let epochs = block_number / ETHASH_EPOCH_LENGTH;
let mut ret: H256 = [0u8; 32];
for _ in 0..epochs {
diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs
index e96b98b81..982f7129b 100644
--- a/ethash/src/lib.rs
+++ b/ethash/src/lib.rs
@@ -24,7 +24,7 @@ mod compute;
use std::mem;
use compute::Light;
-pub use compute::{quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH};
+pub use compute::{get_seedhash, quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH};
use std::sync::{Arc, Mutex};
@@ -35,7 +35,7 @@ struct LightCache {
prev: Option>,
}
-/// Lighy/Full cache manager
+/// Light/Full cache manager.
pub struct EthashManager {
cache: Mutex,
}
diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests
index f32954b3d..99afe8f5a 160000
--- a/ethcore/res/ethereum/tests
+++ b/ethcore/res/ethereum/tests
@@ -1 +1 @@
-Subproject commit f32954b3ddb5af2dc3dc9ec6d9a28bee848fdf70
+Subproject commit 99afe8f5aad7bca5d0f1b1685390a4dea32d73c3
diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs
index 70c6c2fb2..68f647e37 100644
--- a/ethcore/src/block.rs
+++ b/ethcore/src/block.rs
@@ -21,7 +21,7 @@
use common::*;
use engine::*;
use state::*;
-use verification::PreVerifiedBlock;
+use verification::PreverifiedBlock;
/// A block, encoded as it is on the block chain.
// TODO: rename to Block
@@ -155,9 +155,9 @@ pub struct OpenBlock<'x> {
/// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
/// and collected the uncles.
///
-/// There is no function available to push a transaction. If you want that you'll need to `reopen()` it.
-pub struct ClosedBlock<'x> {
- open_block: OpenBlock<'x>,
+/// There is no function available to push a transaction.
+pub struct ClosedBlock {
+ block: ExecutedBlock,
uncle_bytes: Bytes,
}
@@ -178,10 +178,12 @@ impl<'x> OpenBlock<'x> {
last_hashes: last_hashes,
};
- r.block.base.header.set_number(parent.number() + 1);
- r.block.base.header.set_author(author);
- r.block.base.header.set_extra_data(extra_data);
- r.block.base.header.set_timestamp_now();
+ r.block.base.header.parent_hash = parent.hash();
+ r.block.base.header.number = parent.number + 1;
+ r.block.base.header.author = author;
+ r.block.base.header.set_timestamp_now(parent.timestamp());
+ r.block.base.header.extra_data = extra_data;
+ r.block.base.header.note_dirty();
engine.populate_from_parent(&mut r.block.base.header, parent);
engine.on_new_block(&mut r.block);
@@ -218,8 +220,8 @@ impl<'x> OpenBlock<'x> {
/// NOTE Will check chain constraints and the uncle number but will NOT check
/// that the header itself is actually valid.
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
- if self.block.base.uncles.len() >= self.engine.maximum_uncle_count() {
- return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len()}));
+ if self.block.base.uncles.len() + 1 > self.engine.maximum_uncle_count() {
+ return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len() + 1}));
}
// TODO: check number
// TODO: check not a direct ancestor (use last_hashes for that)
@@ -259,7 +261,7 @@ impl<'x> OpenBlock<'x> {
}
/// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles.
- pub fn close(self) -> ClosedBlock<'x> {
+ pub fn close(self) -> ClosedBlock {
let mut s = self;
s.engine.on_close_block(&mut s.block);
s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect());
@@ -271,7 +273,10 @@ impl<'x> OpenBlock<'x> {
s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used);
s.block.base.header.note_dirty();
- ClosedBlock::new(s, uncle_bytes)
+ ClosedBlock {
+ block: s.block,
+ uncle_bytes: uncle_bytes,
+ }
}
}
@@ -279,38 +284,40 @@ impl<'x> IsBlock for OpenBlock<'x> {
fn block(&self) -> &ExecutedBlock { &self.block }
}
-impl<'x> IsBlock for ClosedBlock<'x> {
- fn block(&self) -> &ExecutedBlock { &self.open_block.block }
+impl<'x> IsBlock for ClosedBlock {
+ fn block(&self) -> &ExecutedBlock { &self.block }
}
-impl<'x> ClosedBlock<'x> {
- fn new(open_block: OpenBlock<'x>, uncle_bytes: Bytes) -> Self {
- ClosedBlock {
- open_block: open_block,
- uncle_bytes: uncle_bytes,
- }
- }
-
+impl ClosedBlock {
/// Get the hash of the header without seal arguments.
pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) }
/// Provide a valid seal in order to turn this into a `SealedBlock`.
///
/// NOTE: This does not check the validity of `seal` with the engine.
- pub fn seal(self, seal: Vec) -> Result {
+ pub fn seal(self, engine: &Engine, seal: Vec) -> Result {
let mut s = self;
- if seal.len() != s.open_block.engine.seal_fields() {
- return Err(BlockError::InvalidSealArity(Mismatch{expected: s.open_block.engine.seal_fields(), found: seal.len()}));
+ if seal.len() != engine.seal_fields() {
+ return Err(BlockError::InvalidSealArity(Mismatch{expected: engine.seal_fields(), found: seal.len()}));
}
- s.open_block.block.base.header.set_seal(seal);
- Ok(SealedBlock { block: s.open_block.block, uncle_bytes: s.uncle_bytes })
+ s.block.base.header.set_seal(seal);
+ Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes })
}
- /// Turn this back into an `OpenBlock`.
- pub fn reopen(self) -> OpenBlock<'x> { self.open_block }
+ /// Provide a valid seal in order to turn this into a `SealedBlock`.
+ /// This does check the validity of `seal` with the engine.
+ /// Returns the `ClosedBlock` back again if the seal is no good.
+ pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result {
+ let mut s = self;
+ s.block.base.header.set_seal(seal);
+ match engine.verify_block_seal(&s.block.base.header) {
+ Err(_) => Err(s),
+ _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
+ }
+ }
/// Drop this object and return the underlieing database.
- pub fn drain(self) -> JournalDB { self.open_block.block.state.drop().1 }
+ pub fn drain(self) -> JournalDB { self.block.state.drop().1 }
}
impl SealedBlock {
@@ -332,7 +339,7 @@ impl IsBlock for SealedBlock {
}
/// Enact the block given by block header, transactions and uncles
-pub fn enact<'x>(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> {
+pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result {
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce());
@@ -350,14 +357,14 @@ pub fn enact<'x>(header: &Header, transactions: &[SignedTransaction], uncles: &[
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
-pub fn enact_bytes<'x>(block_bytes: &[u8], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> {
+pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result {
let block = BlockView::new(block_bytes);
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
-pub fn enact_verified<'x>(block: &PreVerifiedBlock, engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result, Error> {
+pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result {
let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes)
}
@@ -365,7 +372,7 @@ pub fn enact_verified<'x>(block: &PreVerifiedBlock, engine: &'x Engine, db: Jour
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: LastHashes) -> Result {
let header = BlockView::new(block_bytes).header_view();
- Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(header.seal())))
+ Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(engine, header.seal())))
}
#[cfg(test)]
@@ -386,7 +393,7 @@ mod tests {
let last_hashes = vec![genesis_header.hash()];
let b = OpenBlock::new(engine.deref(), db, &genesis_header, last_hashes, Address::zero(), vec![]);
let b = b.close();
- let _ = b.seal(vec![]);
+ let _ = b.seal(engine.deref(), vec![]);
}
#[test]
@@ -398,7 +405,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
engine.spec().ensure_db_good(&mut db);
- let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap();
+ let b = OpenBlock::new(engine.deref(), db, &genesis_header, vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs
index de411c6e2..55fd1f676 100644
--- a/ethcore/src/block_queue.rs
+++ b/ethcore/src/block_queue.rs
@@ -28,7 +28,7 @@ use service::*;
use client::BlockStatus;
use util::panics::*;
-known_heap_size!(0, UnVerifiedBlock, VerifyingBlock, PreVerifiedBlock);
+known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock);
const MIN_MEM_LIMIT: usize = 16384;
const MIN_QUEUE_LIMIT: usize = 512;
@@ -105,14 +105,14 @@ pub struct BlockQueue {
max_mem_use: usize,
}
-struct UnVerifiedBlock {
+struct UnverifiedBlock {
header: Header,
bytes: Bytes,
}
struct VerifyingBlock {
hash: H256,
- block: Option,
+ block: Option,
}
struct QueueSignal {
@@ -134,8 +134,8 @@ impl QueueSignal {
struct Verification {
// All locks must be captured in the order declared here.
- unverified: Mutex>,
- verified: Mutex>,
+ unverified: Mutex>,
+ verified: Mutex>,
verifying: Mutex>,
bad: Mutex>,
}
@@ -252,7 +252,7 @@ impl BlockQueue {
}
}
- fn drain_verifying(verifying: &mut VecDeque, verified: &mut VecDeque, bad: &mut HashSet) {
+ fn drain_verifying(verifying: &mut VecDeque, verified: &mut VecDeque, bad: &mut HashSet) {
while !verifying.is_empty() && verifying.front().unwrap().block.is_some() {
let block = verifying.pop_front().unwrap().block.unwrap();
if bad.contains(&block.header.parent_hash) {
@@ -300,31 +300,31 @@ impl BlockQueue {
let h = header.hash();
{
if self.processing.read().unwrap().contains(&h) {
- return Err(ImportError::AlreadyQueued);
+ return Err(x!(ImportError::AlreadyQueued));
}
let mut bad = self.verification.bad.lock().unwrap();
if bad.contains(&h) {
- return Err(ImportError::Bad(None));
+ return Err(x!(ImportError::KnownBad));
}
if bad.contains(&header.parent_hash) {
bad.insert(h.clone());
- return Err(ImportError::Bad(None));
+ return Err(x!(ImportError::KnownBad));
}
}
match verify_block_basic(&header, &bytes, self.engine.deref().deref()) {
Ok(()) => {
self.processing.write().unwrap().insert(h.clone());
- self.verification.unverified.lock().unwrap().push_back(UnVerifiedBlock { header: header, bytes: bytes });
+ self.verification.unverified.lock().unwrap().push_back(UnverifiedBlock { header: header, bytes: bytes });
self.more_to_verify.notify_all();
Ok(h)
},
Err(err) => {
warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err);
self.verification.bad.lock().unwrap().insert(h.clone());
- Err(From::from(err))
+ Err(err)
}
}
}
@@ -362,7 +362,7 @@ impl BlockQueue {
}
/// Removes up to `max` verified blocks from the queue
- pub fn drain(&self, max: usize) -> Vec {
+ pub fn drain(&self, max: usize) -> Vec {
let mut verified = self.verification.verified.lock().unwrap();
let count = min(max, verified.len());
let mut result = Vec::with_capacity(count);
@@ -475,7 +475,7 @@ mod tests {
match duplicate_import {
Err(e) => {
match e {
- ImportError::AlreadyQueued => {},
+ Error::Import(ImportError::AlreadyQueued) => {},
_ => { panic!("must return AlreadyQueued error"); }
}
}
diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs
index 1f478e141..00d7936ec 100644
--- a/ethcore/src/blockchain/blockchain.rs
+++ b/ethcore/src/blockchain/blockchain.rs
@@ -79,7 +79,7 @@ pub trait BlockProvider {
}
/// Get a list of uncles for a given block.
- /// Returns None if block deos not exist.
+ /// Returns None if block does not exist.
fn uncles(&self, hash: &H256) -> Option> {
self.block(hash).map(|bytes| BlockView::new(&bytes).uncles())
}
@@ -231,6 +231,24 @@ impl BlockProvider for BlockChain {
const COLLECTION_QUEUE_SIZE: usize = 8;
+pub struct AncestryIter<'a> {
+ current: H256,
+ chain: &'a BlockChain,
+}
+
+impl<'a> Iterator for AncestryIter<'a> {
+ type Item = H256;
+ fn next(&mut self) -> Option {
+ if self.current.is_zero() {
+ Option::None
+ } else {
+ let mut n = self.chain.block_details(&self.current).unwrap().parent;
+ mem::swap(&mut self.current, &mut n);
+ Some(n)
+ }
+ }
+}
+
impl BlockChain {
/// Create new instance of blockchain from given Genesis
pub fn new(config: BlockChainConfig, genesis: &[u8], path: &Path) -> BlockChain {
@@ -490,6 +508,37 @@ impl BlockChain {
self.extras_db.write(batch).unwrap();
}
+ /// Iterator that lists `first` and then all of `first`'s ancestors, by hash.
+ pub fn ancestry_iter(&self, first: H256) -> Option {
+ if self.is_known(&first) {
+ Some(AncestryIter {
+ current: first,
+ chain: &self,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Given a block's `parent`, find every block header which represents a valid possible uncle.
+ pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> {
+ if !self.is_known(parent) { return None; }
+
+ let mut excluded = HashSet::new();
+ for a in self.ancestry_iter(parent.clone()).unwrap().take(uncle_generations) {
+ excluded.extend(self.uncle_hashes(&a).unwrap().into_iter());
+ excluded.insert(a);
+ }
+
+ let mut ret = Vec::new();
+ for a in self.ancestry_iter(parent.clone()).unwrap().skip(1).take(uncle_generations) {
+ ret.extend(self.block_details(&a).unwrap().children.iter()
+ .filter_map(|h| if excluded.contains(h) { None } else { self.block_header(h) })
+ );
+ }
+ Some(ret)
+ }
+
/// Get inserted block info which is critical to preapre extras updates.
fn block_info(&self, block_bytes: &[u8]) -> BlockInfo {
let block = BlockView::new(block_bytes);
@@ -773,11 +822,11 @@ impl BlockChain {
blocks.shrink_to_fit();
block_details.shrink_to_fit();
- block_hashes.shrink_to_fit();
- transaction_addresses.shrink_to_fit();
- block_logs.shrink_to_fit();
- blocks_blooms.shrink_to_fit();
- block_receipts.shrink_to_fit();
+ block_hashes.shrink_to_fit();
+ transaction_addresses.shrink_to_fit();
+ block_logs.shrink_to_fit();
+ blocks_blooms.shrink_to_fit();
+ block_receipts.shrink_to_fit();
}
if self.cache_size().total() < self.max_cache_size.load(AtomicOrder::Relaxed) { break; }
}
@@ -795,14 +844,15 @@ mod tests {
use blockchain::{BlockProvider, BlockChain, BlockChainConfig};
use tests::helpers::*;
use devtools::*;
- use blockchain::helpers::generators::{ChainGenerator, ChainIterator};
+ use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
use views::BlockView;
#[test]
fn basic_blockchain_insert() {
let mut canon_chain = ChainGenerator::default();
- let genesis = canon_chain.next().unwrap().rlp();
- let first = canon_chain.next().unwrap().rlp();
+ let mut finalizer = BlockFinalizer::default();
+ let genesis = canon_chain.generate(&mut finalizer).unwrap();
+ let first = canon_chain.generate(&mut finalizer).unwrap();
let genesis_hash = BlockView::new(&genesis).header_view().sha3();
let first_hash = BlockView::new(&first).header_view().sha3();
@@ -827,18 +877,76 @@ mod tests {
assert_eq!(bc.block_hash(2), None);
}
+ #[test]
+ fn check_ancestry_iter() {
+ let mut canon_chain = ChainGenerator::default();
+ let mut finalizer = BlockFinalizer::default();
+ let genesis = canon_chain.generate(&mut finalizer).unwrap();
+ let genesis_hash = BlockView::new(&genesis).header_view().sha3();
+
+ let temp = RandomTempPath::new();
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
+
+ let mut block_hashes = vec![genesis_hash.clone()];
+ for _ in 0..10 {
+ let block = canon_chain.generate(&mut finalizer).unwrap();
+ block_hashes.push(BlockView::new(&block).header_view().sha3());
+ bc.insert_block(&block, vec![]);
+ }
+
+ block_hashes.reverse();
+
+ assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).unwrap().collect::>(), block_hashes)
+ }
+
+ #[test]
+ #[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
+ fn test_find_uncles() {
+ let mut canon_chain = ChainGenerator::default();
+ let mut finalizer = BlockFinalizer::default();
+ let genesis = canon_chain.generate(&mut finalizer).unwrap();
+ let b1b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
+ let b1a = canon_chain.generate(&mut finalizer).unwrap();
+ let b2b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
+ let b2a = canon_chain.generate(&mut finalizer).unwrap();
+ let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
+ let b3a = canon_chain.generate(&mut finalizer).unwrap();
+ let b4b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
+ let b4a = canon_chain.generate(&mut finalizer).unwrap();
+ let b5b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
+ let b5a = canon_chain.generate(&mut finalizer).unwrap();
+
+ let temp = RandomTempPath::new();
+ let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
+ bc.insert_block(&b1a, vec![]);
+ bc.insert_block(&b1b, vec![]);
+ bc.insert_block(&b2a, vec![]);
+ bc.insert_block(&b2b, vec![]);
+ bc.insert_block(&b3a, vec![]);
+ bc.insert_block(&b3b, vec![]);
+ bc.insert_block(&b4a, vec![]);
+ bc.insert_block(&b4b, vec![]);
+ bc.insert_block(&b5a, vec![]);
+ bc.insert_block(&b5b, vec![]);
+
+ assert_eq!(
+ [&b4b, &b3b, &b2b].iter().map(|b| BlockView::new(b).header()).collect::>(),
+ bc.find_uncle_headers(&BlockView::new(&b4a).header_view().sha3(), 3).unwrap()
+ );
+
+ // TODO: insert block that already includes one of them as an uncle to check it's not allowed.
+ }
+
#[test]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn test_small_fork() {
let mut canon_chain = ChainGenerator::default();
- let genesis = canon_chain.next().unwrap().rlp();
- let blocks = canon_chain.clone().take(3).map(|block| block.rlp()).collect::>();
- let fork = canon_chain.skip(2).fork(1).take(1).next().unwrap().rlp();
-
- let b1 = blocks[0].clone();
- let b2 = blocks[1].clone();
- let b3a = blocks[2].clone();
- let b3b = fork;
+ let mut finalizer = BlockFinalizer::default();
+ let genesis = canon_chain.generate(&mut finalizer).unwrap();
+ let b1 = canon_chain.generate(&mut finalizer).unwrap();
+ let b2 = canon_chain.generate(&mut finalizer).unwrap();
+ let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
+ let b3a = canon_chain.generate(&mut finalizer).unwrap();
let genesis_hash = BlockView::new(&genesis).header_view().sha3();
let b1_hash= BlockView::new(&b1).header_view().sha3();
@@ -922,22 +1030,24 @@ mod tests {
#[test]
fn test_reopen_blockchain_db() {
- let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap();
- let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap();
- let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap();
- let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap();
+ let mut canon_chain = ChainGenerator::default();
+ let mut finalizer = BlockFinalizer::default();
+ let genesis = canon_chain.generate(&mut finalizer).unwrap();
+ let first = canon_chain.generate(&mut finalizer).unwrap();
+ let genesis_hash = BlockView::new(&genesis).header_view().sha3();
+ let first_hash = BlockView::new(&first).header_view().sha3();
let temp = RandomTempPath::new();
{
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
assert_eq!(bc.best_block_hash(), genesis_hash);
- bc.insert_block(&b1, vec![]);
- assert_eq!(bc.best_block_hash(), b1_hash);
+ bc.insert_block(&first, vec![]);
+ assert_eq!(bc.best_block_hash(), first_hash);
}
{
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
- assert_eq!(bc.best_block_hash(), b1_hash);
+ assert_eq!(bc.best_block_hash(), first_hash);
}
}
@@ -1001,29 +1111,24 @@ mod tests {
#[test]
fn test_bloom_filter_simple() {
- let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap();
-
- // block b1 (child of genesis)
- let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000200000000000000000000000000000000000000000020000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080004000000000000000000000020008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap();
-
- // block b2 (child of b1)
- let b2 = "f902ccf901f9a04ef46c05763fffc5f7e59f92a7ef438ffccbb578e6e5d0f04e3df8a7fa6c02f6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
-
- // prepare for fork (b1a, child of genesis)
- let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
-
- // fork (b2a, child of b1a, with higher total difficulty)
- let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
-
- // fork back :)
- let b3 = "f902ccf901f9a0e6cd7250e4c32b33c906aca30280911c560ac67bd0a05fbeb874f99ac7e7e47aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004003832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
-
+ // TODO: From here
let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap();
let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let bloom_ba = H2048::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
+ let mut canon_chain = ChainGenerator::default();
+ let mut finalizer = BlockFinalizer::default();
+ let genesis = canon_chain.generate(&mut finalizer).unwrap();
+ let mut fork = canon_chain.fork(1);
+ let mut fork_finalizer = finalizer.fork();
+ let b1 = fork.with_bloom(bloom_b1.clone()).generate(&mut fork_finalizer).unwrap();
+ let b2 = fork.with_bloom(bloom_b2.clone()).generate(&mut fork_finalizer).unwrap();
+ let b3 = fork.with_bloom(bloom_ba.clone()).generate(&mut fork_finalizer).unwrap();
+ let b1a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap();
+ let b2a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap();
+
let temp = RandomTempPath::new();
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
diff --git a/ethcore/src/blockchain/generator/block.rs b/ethcore/src/blockchain/generator/block.rs
new file mode 100644
index 000000000..0a3dad399
--- /dev/null
+++ b/ethcore/src/blockchain/generator/block.rs
@@ -0,0 +1,64 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+use util::rlp::*;
+use util::{H256, H2048};
+use util::U256;
+use util::bytes::Bytes;
+use header::Header;
+use transaction::SignedTransaction;
+
+use super::fork::Forkable;
+use super::bloom::WithBloom;
+use super::complete::CompleteBlock;
+
+/// Helper structure, used for encoding blocks.
+#[derive(Default)]
+pub struct Block {
+ pub header: Header,
+ pub transactions: Vec,
+ pub uncles: Vec
+}
+
+impl Encodable for Block {
+ fn rlp_append(&self, s: &mut RlpStream) {
+ s.begin_list(3);
+ s.append(&self.header);
+ s.append(&self.transactions);
+ s.append(&self.uncles);
+ }
+}
+
+impl Forkable for Block {
+ fn fork(mut self, fork_number: usize) -> Self where Self: Sized {
+ self.header.difficulty = self.header.difficulty - U256::from(fork_number);
+ self
+ }
+}
+
+impl WithBloom for Block {
+ fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized {
+ self.header.log_bloom = bloom;
+ self
+ }
+}
+
+impl CompleteBlock for Block {
+ fn complete(mut self, parent_hash: H256) -> Bytes {
+ self.header.parent_hash = parent_hash;
+ encode(&self).to_vec()
+ }
+}
diff --git a/ethcore/src/blockchain/generator/bloom.rs b/ethcore/src/blockchain/generator/bloom.rs
new file mode 100644
index 000000000..f61c9d1ff
--- /dev/null
+++ b/ethcore/src/blockchain/generator/bloom.rs
@@ -0,0 +1,35 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+use util::hash::H2048;
+
+pub trait WithBloom {
+ fn with_bloom(self, bloom: H2048) -> Self where Self: Sized;
+}
+
+pub struct Bloom<'a, I> where I: 'a {
+ pub iter: &'a mut I,
+ pub bloom: H2048,
+}
+
+impl<'a, I> Iterator for Bloom<'a, I> where I: Iterator, ::Item: WithBloom {
+ type Item = ::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option {
+ self.iter.next().map(|item| item.with_bloom(self.bloom.clone()))
+ }
+}
diff --git a/ethcore/src/blockchain/generator/complete.rs b/ethcore/src/blockchain/generator/complete.rs
new file mode 100644
index 000000000..39bd587a0
--- /dev/null
+++ b/ethcore/src/blockchain/generator/complete.rs
@@ -0,0 +1,53 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+use util::hash::H256;
+use util::bytes::Bytes;
+use util::sha3::Hashable;
+use views::BlockView;
+
+#[derive(Default, Clone)]
+pub struct BlockFinalizer {
+ parent_hash: H256
+}
+
+impl BlockFinalizer {
+ pub fn fork(&self) -> Self {
+ self.clone()
+ }
+}
+
+pub trait CompleteBlock {
+ fn complete(self, parent_hash: H256) -> Bytes;
+}
+
+pub struct Complete<'a, I> where I: 'a {
+ pub iter: &'a mut I,
+ pub finalizer: &'a mut BlockFinalizer,
+}
+
+impl<'a, I> Iterator for Complete<'a, I> where I: Iterator, ::Item: CompleteBlock {
+ type Item = Bytes;
+
+ #[inline]
+ fn next(&mut self) -> Option {
+ self.iter.next().map(|item| {
+ let rlp = item.complete(self.finalizer.parent_hash.clone());
+ self.finalizer.parent_hash = BlockView::new(&rlp).header_view().sha3();
+ rlp
+ })
+ }
+}
diff --git a/ethcore/src/blockchain/generator/fork.rs b/ethcore/src/blockchain/generator/fork.rs
new file mode 100644
index 000000000..f3a4eb267
--- /dev/null
+++ b/ethcore/src/blockchain/generator/fork.rs
@@ -0,0 +1,42 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+pub trait Forkable {
+ fn fork(self, fork_number: usize) -> Self where Self: Sized;
+}
+
+pub struct Fork {
+ pub iter: I,
+ pub fork_number: usize,
+}
+
+impl Clone for Fork where I: Iterator + Clone {
+ fn clone(&self) -> Self {
+ Fork {
+ iter: self.iter.clone(),
+ fork_number: self.fork_number
+ }
+ }
+}
+
+impl Iterator for Fork where I: Iterator, ::Item: Forkable {
+ type Item = ::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option {
+ self.iter.next().map(|item| item.fork(self.fork_number))
+ }
+}
diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/generator/generator.rs
similarity index 51%
rename from ethcore/src/blockchain/helpers/generators.rs
rename to ethcore/src/blockchain/generator/generator.rs
index a20b0cf79..51e6294fc 100644
--- a/ethcore/src/blockchain/helpers/generators.rs
+++ b/ethcore/src/blockchain/generator/generator.rs
@@ -14,108 +14,52 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use util::rlp::*;
-use util::hash::{H256, H2048};
-use util::uint::{U256};
+use util::hash::H2048;
+use util::numbers::U256;
use util::bytes::Bytes;
-use header::{BlockNumber, Header};
-use transaction::SignedTransaction;
-
-pub trait Forkable {
- fn fork(self, fork_number: usize) -> Self where Self: Sized;
-}
-
-pub struct Fork {
- iter: I,
- fork_number: usize,
-}
-
-impl Iterator for Fork where I: Iterator, ::Item: Forkable {
- type Item = ::Item;
-
- #[inline]
- fn next(&mut self) -> Option {
- self.iter.next().map(|item| item.fork(self.fork_number))
- }
-}
-
-pub trait WithBloom {
- fn with_bloom(self, bloom: H2048) -> Self where Self: Sized;
-}
-
-pub struct Bloom {
- iter: I,
- bloom: H2048,
-}
-
-impl Iterator for Bloom where I: Iterator, ::Item: WithBloom {
- type Item = ::Item;
-
- #[inline]
- fn next(&mut self) -> Option {
- self.iter.next().map(|item| item.with_bloom(self.bloom.clone()))
- }
-}
+use header::BlockNumber;
+use super::fork::Fork;
+use super::bloom::Bloom;
+use super::complete::{BlockFinalizer, CompleteBlock, Complete};
+use super::block::Block;
/// Chain iterator interface.
-pub trait ChainIterator: Iterator {
+pub trait ChainIterator: Iterator + Sized {
/// Should be called to create a fork of current iterator.
/// Blocks generated by fork will have lower difficulty than current chain.
- fn fork(&mut self, fork_number: usize) -> Fork where Self: Sized;
+ fn fork(&self, fork_number: usize) -> Fork where Self: Clone;
/// Should be called to make every consecutive block have given bloom.
- fn with_bloom(&mut self, bloom: H2048) -> Bloom where Self: Sized;
+ fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self>;
+ /// Should be called to complete block. Without complete, block may have incorrect hash.
+ fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>;
+ /// Completes and generates block.
+ fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where Self::Item: CompleteBlock;
}
-impl ChainIterator for I where I: Iterator + Sized + Clone {
- fn fork(&mut self, fork_number: usize) -> Fork {
+impl ChainIterator for I where I: Iterator + Sized {
+ fn fork(&self, fork_number: usize) -> Fork where I: Clone {
Fork {
iter: self.clone(),
fork_number: fork_number
}
}
- fn with_bloom(&mut self, bloom: H2048) -> Bloom {
+ fn with_bloom<'a>(&'a mut self, bloom: H2048) -> Bloom<'a, Self> {
Bloom {
- iter: self.clone(),
+ iter: self,
bloom: bloom
}
}
-}
-/// Helper structure, used for encoding blocks.
-#[derive(Default)]
-pub struct Block {
- header: Header,
- transactions: Vec,
- uncles: Vec
-}
-
-impl Block {
- pub fn rlp(&self) -> Bytes {
- encode(self).to_vec()
+ fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self> {
+ Complete {
+ iter: self,
+ finalizer: finalizer
+ }
}
-}
-impl Encodable for Block {
- fn rlp_append(&self, s: &mut RlpStream) {
- s.begin_list(3);
- s.append(&self.header);
- s.append(&self.transactions);
- s.append(&self.uncles);
- }
-}
-
-impl Forkable for Block {
- fn fork(mut self, fork_number: usize) -> Self where Self: Sized {
- self.header.difficulty = self.header.difficulty - U256::from(fork_number);
- self
- }
-}
-
-impl WithBloom for Block {
- fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized {
- self.header.log_bloom = bloom;
- self
+ fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where ::Item: CompleteBlock {
+ self.complete(finalizer).next()
}
}
@@ -124,8 +68,6 @@ impl WithBloom for Block {
pub struct ChainGenerator {
/// Next block number.
number: BlockNumber,
- /// Next block parent hash.
- parent_hash: H256,
/// Next block difficulty.
difficulty: U256,
}
@@ -133,7 +75,6 @@ pub struct ChainGenerator {
impl ChainGenerator {
fn prepare_block(&self) -> Block {
let mut block = Block::default();
- block.header.parent_hash = self.parent_hash.clone();
block.header.number = self.number;
block.header.difficulty = self.difficulty;
block
@@ -144,7 +85,6 @@ impl Default for ChainGenerator {
fn default() -> Self {
ChainGenerator {
number: 0,
- parent_hash: H256::default(),
difficulty: U256::from(1000),
}
}
@@ -156,30 +96,28 @@ impl Iterator for ChainGenerator {
fn next(&mut self) -> Option {
let block = self.prepare_block();
self.number += 1;
- self.parent_hash = block.header.hash();
Some(block)
}
}
-
-#[cfg(test)]
mod tests {
- use util::hash::H256;
+ use util::hash::{H256, H2048};
use util::sha3::Hashable;
use views::BlockView;
- use super::{ChainIterator, ChainGenerator};
+ use blockchain::generator::{ChainIterator, ChainGenerator, BlockFinalizer};
#[test]
fn canon_chain_generator() {
let mut canon_chain = ChainGenerator::default();
+ let mut finalizer = BlockFinalizer::default();
- let genesis_rlp = canon_chain.next().unwrap().rlp();
+ let genesis_rlp = canon_chain.generate(&mut finalizer).unwrap();
let genesis = BlockView::new(&genesis_rlp);
assert_eq!(genesis.header_view().parent_hash(), H256::default());
assert_eq!(genesis.header_view().number(), 0);
- let b1_rlp = canon_chain.next().unwrap().rlp();
+ let b1_rlp = canon_chain.generate(&mut finalizer).unwrap();
let b1 = BlockView::new(&b1_rlp);
assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3());
@@ -187,17 +125,45 @@ mod tests {
let mut fork_chain = canon_chain.fork(1);
- let b2_rlp_fork = fork_chain.next().unwrap().rlp();
+ let b2_rlp_fork = fork_chain.generate(&mut finalizer.fork()).unwrap();
let b2_fork = BlockView::new(&b2_rlp_fork);
assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3());
assert_eq!(b2_fork.header_view().number(), 2);
- let b2_rlp = canon_chain.next().unwrap().rlp();
+ let b2_rlp = canon_chain.generate(&mut finalizer).unwrap();
let b2 = BlockView::new(&b2_rlp);
assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3());
assert_eq!(b2.header_view().number(), 2);
assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty());
}
+
+ #[test]
+ fn with_bloom_generator() {
+ let bloom = H2048([0x1; 256]);
+ let mut gen = ChainGenerator::default();
+ let mut finalizer = BlockFinalizer::default();
+
+ let block0_rlp = gen.with_bloom(bloom).generate(&mut finalizer).unwrap();
+ let block1_rlp = gen.generate(&mut finalizer).unwrap();
+ let block0 = BlockView::new(&block0_rlp);
+ let block1 = BlockView::new(&block1_rlp);
+
+ assert_eq!(block0.header_view().number(), 0);
+ assert_eq!(block0.header_view().parent_hash(), H256::default());
+
+ assert_eq!(block1.header_view().number(), 1);
+ assert_eq!(block1.header_view().parent_hash(), block0.header_view().sha3());
+
+ }
+
+ #[test]
+ fn generate_1000_blocks() {
+ let generator = ChainGenerator::default();
+ let mut finalizer = BlockFinalizer::default();
+ let blocks: Vec<_> = generator.take(1000).complete(&mut finalizer).collect();
+ assert_eq!(blocks.len(), 1000);
+ }
}
+
diff --git a/ethcore/src/blockchain/generator/mod.rs b/ethcore/src/blockchain/generator/mod.rs
new file mode 100644
index 000000000..88fdec0e4
--- /dev/null
+++ b/ethcore/src/blockchain/generator/mod.rs
@@ -0,0 +1,24 @@
+// Copyright 2015, 2016 Ethcore (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+mod bloom;
+mod block;
+mod complete;
+mod fork;
+pub mod generator;
+
+pub use self::complete::BlockFinalizer;
+pub use self::generator::{ChainIterator, ChainGenerator};
diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs
index 60a1aeb33..b0679b563 100644
--- a/ethcore/src/blockchain/mod.rs
+++ b/ethcore/src/blockchain/mod.rs
@@ -24,7 +24,7 @@ mod cache;
mod tree_route;
mod update;
#[cfg(test)]
-mod helpers;
+mod generator;
pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig};
pub use self::cache::CacheSize;
diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs
index fb6df877a..387d750fd 100644
--- a/ethcore/src/chainfilter/chainfilter.rs
+++ b/ethcore/src/chainfilter/chainfilter.rs
@@ -15,7 +15,7 @@
// along with Parity. If not, see .
//! Multilevel blockchain bloom filter.
-//!
+//!
//! ```not_run
//! extern crate ethcore_util as util;
//! extern crate ethcore;
@@ -23,33 +23,33 @@
//! use util::sha3::*;
//! use util::hash::*;
//! use ethcore::chainfilter::*;
-//!
+//!
//! fn main() {
//! let (index_size, bloom_levels) = (16, 3);
//! let mut cache = MemoryCache::new();
-//!
+//!
//! let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap();
-//!
+//!
//! // borrow cache for reading inside the scope
//! let modified_blooms = {
-//! let filter = ChainFilter::new(&cache, index_size, bloom_levels);
+//! let filter = ChainFilter::new(&cache, index_size, bloom_levels);
//! let block_number = 39;
//! let mut bloom = H2048::new();
//! bloom.shift_bloomed(&address.sha3());
//! filter.add_bloom(&bloom, block_number)
//! };
-//!
+//!
//! // number of updated blooms is equal number of levels
//! assert_eq!(modified_blooms.len(), bloom_levels as usize);
//!
//! // lets inserts modified blooms into the cache
//! cache.insert_blooms(modified_blooms);
-//!
+//!
//! // borrow cache for another reading operations
//! {
-//! let filter = ChainFilter::new(&cache, index_size, bloom_levels);
+//! let filter = ChainFilter::new(&cache, index_size, bloom_levels);
//! let blocks = filter.blocks_with_address(&address, 10, 40);
-//! assert_eq!(blocks.len(), 1);
+//! assert_eq!(blocks.len(), 1);
//! assert_eq!(blocks[0], 39);
//! }
//! }
@@ -71,7 +71,7 @@ pub struct ChainFilter<'a, D>
impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource
{
/// Creates new filter instance.
- ///
+ ///
/// Borrows `FilterDataSource` for reading.
pub fn new(data_source: &'a D, index_size: usize, levels: u8) -> Self {
ChainFilter {
@@ -88,7 +88,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource
None => return None,
Some(level_bloom) => match level {
// if we are on the lowest level
- 0 => return match offset < to_block {
+ 0 => return match offset <= to_block {
// take the value if its smaller than to_block
true if level_bloom.contains(bloom) => Some(vec![offset]),
// return None if it is is equal to to_block
@@ -153,7 +153,7 @@ impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource
for i in 0..blooms.len() {
let index = self.indexer.bloom_index(block_number + i, level);
- let new_bloom = {
+ let new_bloom = {
// use new blooms before db blooms where necessary
let bloom_at = | index | { result.get(&index).cloned().or_else(|| self.data_source.bloom_at_index(&index)) };
diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs
index 2baa93e55..08af44720 100644
--- a/ethcore/src/chainfilter/tests.rs
+++ b/ethcore/src/chainfilter/tests.rs
@@ -22,7 +22,7 @@ use util::sha3::*;
use chainfilter::{BloomIndex, FilterDataSource, ChainFilter};
/// In memory cache for blooms.
-///
+///
/// Stores all blooms in HashMap, which indexes them by `BloomIndex`.
pub struct MemoryCache {
blooms: HashMap,
@@ -35,7 +35,7 @@ impl MemoryCache {
}
/// inserts all blooms into cache
- ///
+ ///
/// if bloom at given index already exists, overwrites it
pub fn insert_blooms(&mut self, blooms: HashMap) {
self.blooms.extend(blooms);
@@ -81,13 +81,13 @@ fn test_topic_basic_search() {
{
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
- let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 23);
+ let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 22);
assert_eq!(blocks.len(), 0);
}
{
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
- let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 23, 24);
+ let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 23, 23);
assert_eq!(blocks.len(), 1);
assert_eq!(blocks[0], 23);
}
@@ -144,7 +144,7 @@ fn test_reset_chain_head_simple() {
cache.insert_blooms(modified_blooms_3);
-
+
let reset_modified_blooms = {
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
filter.reset_chain_head(&[to_bloom(&topic_4), to_bloom(&topic_5)], 15, 17)
@@ -183,7 +183,7 @@ fn for_each_bloom(bytes: &[u8], mut f: F) where F: FnMut(usize, &H2048) {
}
fn for_each_log(bytes: &[u8], mut f: F) where F: FnMut(usize, &Address, &[H256]) {
- let mut reader = BufReader::new(bytes);
+ let mut reader = BufReader::new(bytes);
let mut line = String::new();
while reader.read_line(&mut line).unwrap() > 0 {
{
@@ -235,11 +235,11 @@ fn test_chainfilter_real_data_short_searches() {
for_each_log(include_bytes!("logs.txt"), | block_number, address, topics | {
println!("block_number: {:?}", block_number);
let filter = ChainFilter::new(&cache, index_size, bloom_levels);
- let blocks = filter.blocks_with_bloom(&to_bloom(address), block_number, block_number + 1);
+ let blocks = filter.blocks_with_bloom(&to_bloom(address), block_number, block_number);
assert_eq!(blocks.len(), 1);
for (i, topic) in topics.iter().enumerate() {
println!("topic: {:?}", i);
- let blocks = filter.blocks_with_bloom(&to_bloom(topic), block_number, block_number + 1);
+ let blocks = filter.blocks_with_bloom(&to_bloom(topic), block_number, block_number);
assert_eq!(blocks.len(), 1);
}
});
diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs
index 65db6e0e6..4f37f2a7d 100644
--- a/ethcore/src/client.rs
+++ b/ethcore/src/client.rs
@@ -16,12 +16,14 @@
//! Blockchain database client.
+use std::marker::PhantomData;
+use std::sync::atomic::AtomicBool;
use util::*;
use util::panics::*;
use blockchain::{BlockChain, BlockProvider};
use views::BlockView;
use error::*;
-use header::{BlockNumber, Header};
+use header::{BlockNumber};
use state::State;
use spec::Spec;
use engine::Engine;
@@ -35,6 +37,7 @@ use transaction::LocalizedTransaction;
use extras::TransactionAddress;
use filter::Filter;
use log_entry::LocalizedLogEntry;
+use util::keys::store::SecretStore;
pub use block_queue::{BlockQueueConfig, BlockQueueInfo};
pub use blockchain::{TreeRoute, BlockChainConfig, CacheSize as BlockChainCacheSize};
@@ -76,12 +79,24 @@ pub enum BlockStatus {
}
/// Client configuration. Includes configs for all sub-systems.
-#[derive(Debug, Default)]
+#[derive(Debug)]
pub struct ClientConfig {
/// Block queue configuration.
pub queue: BlockQueueConfig,
/// Blockchain configuration.
pub blockchain: BlockChainConfig,
+ /// Prefer journal rather than archive.
+ pub prefer_journal: bool,
+}
+
+impl Default for ClientConfig {
+ fn default() -> ClientConfig {
+ ClientConfig {
+ queue: Default::default(),
+ blockchain: Default::default(),
+ prefer_journal: false,
+ }
+ }
}
/// Information about the blockchain gathered together.
@@ -123,6 +138,9 @@ pub trait BlockChainClient : Sync + Send {
/// Get block total difficulty.
fn block_total_difficulty(&self, id: BlockId) -> Option;
+ /// Get block hash.
+ fn block_hash(&self, id: BlockId) -> Option;
+
/// Get address code.
fn code(&self, address: &Address) -> Option;
@@ -176,7 +194,7 @@ pub struct ClientReport {
impl ClientReport {
/// Alter internal reporting to reflect the additional `block` has been processed.
- pub fn accrue_block(&mut self, block: &PreVerifiedBlock) {
+ pub fn accrue_block(&mut self, block: &PreverifiedBlock) {
self.blocks_imported += 1;
self.transactions_applied += block.transactions.len();
self.gas_processed = self.gas_processed + block.header.gas_used;
@@ -185,7 +203,7 @@ impl ClientReport {
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
-pub struct Client {
+pub struct Client where V: Verifier {
chain: Arc,
engine: Arc>,
state_db: Mutex,
@@ -193,18 +211,33 @@ pub struct Client {
report: RwLock,
import_lock: Mutex<()>,
panic_handler: Arc,
+
+ // for sealing...
+ sealing_enabled: AtomicBool,
+ sealing_block: Mutex