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 510e69b59..55ed996ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -146,14 +146,6 @@ dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "deque"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "docopt"
version = "0.6.78"
@@ -293,7 +285,6 @@ dependencies = [
"heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -664,16 +655,6 @@ dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "rayon"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "regex"
version = "0.1.54"
diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs
index f5788baba..68f647e37 100644
--- a/ethcore/src/block.rs
+++ b/ethcore/src/block.rs
@@ -220,8 +220,8 @@ impl<'x> OpenBlock<'x> {
/// NOTE Will check chain constraints and the uncle number but will NOT check
/// that the header itself is actually valid.
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
- if self.block.base.uncles.len() >= self.engine.maximum_uncle_count() {
- return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len()}));
+ if self.block.base.uncles.len() + 1 > self.engine.maximum_uncle_count() {
+ return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len() + 1}));
}
// TODO: check number
// TODO: check not a direct ancestor (use last_hashes for that)
diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs
index f412a8240..e529f50af 100644
--- a/ethcore/src/blockchain/blockchain.rs
+++ b/ethcore/src/blockchain/blockchain.rs
@@ -78,7 +78,7 @@ pub trait BlockProvider {
}
/// Get a list of uncles for a given block.
- /// Returns None if block deos not exist.
+ /// Returns None if block does not exist.
fn uncles(&self, hash: &H256) -> Option> {
self.block(hash).map(|bytes| BlockView::new(&bytes).uncles())
}
@@ -227,6 +227,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 {
@@ -474,10 +492,35 @@ impl BlockChain {
self.extras_db.write(batch).unwrap();
}
- /// Given a block's `parent`, find every block header which represents a valid uncle.
- pub fn find_uncle_headers(&self, _parent: &H256) -> Vec {
- // TODO
- Vec::new()
+ /// 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.
@@ -818,6 +861,66 @@ 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() {
diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs
index 878bacce9..858185873 100644
--- a/ethcore/src/client.rs
+++ b/ethcore/src/client.rs
@@ -17,6 +17,7 @@
//! Blockchain database client.
use std::marker::PhantomData;
+use std::sync::atomic::AtomicBool;
use util::*;
use util::panics::*;
use blockchain::{BlockChain, BlockProvider};
@@ -137,9 +138,6 @@ pub trait BlockChainClient : Sync + Send {
/// Get block total difficulty.
fn block_total_difficulty(&self, id: BlockId) -> Option;
- /// Get address nonce.
- fn nonce(&self, address: &Address) -> U256;
-
/// Get block hash.
fn block_hash(&self, id: BlockId) -> Option;
@@ -215,6 +213,7 @@ pub struct Client where V: Verifier {
panic_handler: Arc,
// for sealing...
+ sealing_enabled: AtomicBool,
sealing_block: Mutex