From 039c0056bc0f58bfe33860c7a4aab7b9aff57bbc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 2 Mar 2016 19:38:00 +0100 Subject: [PATCH] Uncle inclusion in block authoring. Still need tests. --- ethcore/src/blockchain/blockchain.rs | 46 +++++++++------------------- ethcore/src/client.rs | 2 +- ethcore/src/engine.rs | 2 ++ ethcore/src/verification.rs | 4 +-- 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 6b0939df5..4cf2d96c5 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -503,41 +503,23 @@ impl BlockChain { } } - /// Given a block's `parent`, find every block header which represents a valid uncle. - pub fn find_uncle_headers(&self, parent: &H256) -> Option> { - let uncle_generations = 6usize; -/* - { - // Find great-uncles (or second-cousins or whatever they are) - - // children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. - clog(StateDetail) << "Checking " << m_previousBlock.hash() << ", parent=" << m_previousBlock.parentHash(); - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); - auto p = m_previousBlock.parentHash(); - for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) - { - auto us = _bc.details(p).children; - assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent! - for (auto const& u: us) - if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. - { - uncleBlockHeaders.push_back(_bc.info(u)); - unclesData.appendRaw(_bc.headerData(u)); - ++unclesCount; - if (unclesCount == 2) - break; - } - } - } -*/ + /// Given a block's `parent`, find every block header which represents a valid possible uncle. + pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { if !self.is_known(parent) { return None; } - let mut _excluded = HashSet::new(); + + let mut excluded = HashSet::new(); for a in self.ancestry_iter(parent.clone()).unwrap().take(uncle_generations) { - for u in self.uncle_hashes(&a).unwrap().into_iter() { - _excluded.insert(u); - } - _excluded.insert(a); + excluded.extend(self.uncle_hashes(&a).unwrap().into_iter()); + excluded.insert(a); } - None + + let mut ret = Vec::new(); + for a in self.ancestry_iter(parent.clone()).unwrap().skip(1).take(uncle_generations) { + ret.extend(self.block_details(&a).unwrap().children.iter() + .filter_map(|h| if excluded.contains(h) { None } else { self.block_header(h) }) + ); + } + Some(ret) } /// Get inserted block info which is critical to preapre extras updates. diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 105090580..4ddb40477 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -457,7 +457,7 @@ impl Client { self.extra_data() ); - self.chain.read().unwrap().find_uncle_headers(&h).unwrap().into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); + self.chain.read().unwrap().find_uncle_headers(&h, self.engine.deref().deref().maximum_uncle_age()).unwrap().into_iter().foreach(|h| { b.push_uncle(h).unwrap(); }); // TODO: push transactions. diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index d607ce2e2..83e1986fd 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -47,6 +47,8 @@ pub trait Engine : Sync + Send { fn maximum_extra_data_size(&self) -> usize { decode(&self.spec().engine_params.get("maximumExtraDataSize").unwrap()) } /// Maximum number of uncles a block is allowed to declare. fn maximum_uncle_count(&self) -> usize { 2 } + /// The number of generations back that uncles can be. + fn maximum_uncle_age(&self) -> usize { 6 } /// The nonce with which accounts begin. fn account_start_nonce(&self) -> U256 { decode(&self.spec().engine_params.get("accountStartNonce").unwrap()) } diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index f52e2e1e4..23b850f55 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -94,7 +94,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b excluded.insert(header.hash()); let mut hash = header.parent_hash.clone(); excluded.insert(hash.clone()); - for _ in 0..6 { + for _ in 0..engine.maximum_uncle_age() { match bc.block_details(&hash) { Some(details) => { excluded.insert(details.parent.clone()); @@ -121,7 +121,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b // (8 Invalid) let depth = if header.number > uncle.number { header.number - uncle.number } else { 0 }; - if depth > 6 { + if depth > engine.maximum_uncle_age() as u64 { return Err(From::from(BlockError::UncleTooOld(OutOfBounds { min: Some(header.number - depth), max: Some(header.number - 1), found: uncle.number }))); } else if depth < 1 {