Merge pull request #645 from ethcore/import_route

blockchain import_route
This commit is contained in:
Gav Wood 2016-03-10 13:14:56 +01:00
commit 16e12b1ae5
4 changed files with 169 additions and 17 deletions

View File

@ -18,6 +18,7 @@ use util::numbers::{U256,H256};
use header::BlockNumber; use header::BlockNumber;
/// Brief info about inserted block. /// Brief info about inserted block.
#[derive(Clone)]
pub struct BlockInfo { pub struct BlockInfo {
/// Block hash. /// Block hash.
pub hash: H256, pub hash: H256,
@ -30,6 +31,7 @@ pub struct BlockInfo {
} }
/// Describes location of newly inserted block. /// Describes location of newly inserted block.
#[derive(Clone)]
pub enum BlockLocation { pub enum BlockLocation {
/// It's part of the canon chain. /// It's part of the canon chain.
CanonChain, CanonChain,
@ -42,6 +44,8 @@ pub enum BlockLocation {
/// Hash of the newest common ancestor with old canon chain. /// Hash of the newest common ancestor with old canon chain.
ancestor: H256, ancestor: H256,
/// Hashes of the blocks between ancestor and this block. /// Hashes of the blocks between ancestor and this block.
route: Vec<H256> enacted: Vec<H256>,
/// Hashes of the blocks which were invalidated.
retracted: Vec<H256>,
} }
} }

View File

@ -28,7 +28,7 @@ use blockchain::best_block::BestBlock;
use blockchain::bloom_indexer::BloomIndexer; use blockchain::bloom_indexer::BloomIndexer;
use blockchain::tree_route::TreeRoute; use blockchain::tree_route::TreeRoute;
use blockchain::update::ExtrasUpdate; use blockchain::update::ExtrasUpdate;
use blockchain::CacheSize; use blockchain::{CacheSize, ImportRoute};
const BLOOM_INDEX_SIZE: usize = 16; const BLOOM_INDEX_SIZE: usize = 16;
const BLOOM_LEVELS: u8 = 3; const BLOOM_LEVELS: u8 = 3;
@ -414,14 +414,14 @@ impl BlockChain {
/// Inserts the block into backing cache database. /// Inserts the block into backing cache database.
/// Expects the block to be valid and already verified. /// Expects the block to be valid and already verified.
/// If the block is already known, does nothing. /// If the block is already known, does nothing.
pub fn insert_block(&self, bytes: &[u8], receipts: Vec<Receipt>) { pub fn insert_block(&self, bytes: &[u8], receipts: Vec<Receipt>) -> ImportRoute {
// create views onto rlp // create views onto rlp
let block = BlockView::new(bytes); let block = BlockView::new(bytes);
let header = block.header_view(); let header = block.header_view();
let hash = header.sha3(); let hash = header.sha3();
if self.is_known(&hash) { if self.is_known(&hash) {
return; return ImportRoute::none();
} }
// store block in db // store block in db
@ -435,8 +435,10 @@ impl BlockChain {
block_receipts: self.prepare_block_receipts_update(receipts, &info), block_receipts: self.prepare_block_receipts_update(receipts, &info),
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
blocks_blooms: self.prepare_block_blooms_update(bytes, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
info: info info: info.clone(),
}); });
ImportRoute::from(info)
} }
/// Applies extras update. /// Applies extras update.
@ -549,9 +551,14 @@ impl BlockChain {
match route.blocks.len() { match route.blocks.len() {
0 => BlockLocation::CanonChain, 0 => BlockLocation::CanonChain,
_ => BlockLocation::BranchBecomingCanonChain { _ => {
ancestor: route.ancestor, let retracted = route.blocks.iter().take(route.index).cloned().collect::<Vec<H256>>();
route: route.blocks.into_iter().skip(route.index).collect()
BlockLocation::BranchBecomingCanonChain {
ancestor: route.ancestor,
enacted: route.blocks.into_iter().skip(route.index).collect(),
retracted: retracted.into_iter().rev().collect(),
}
} }
} }
} else { } else {
@ -572,11 +579,11 @@ impl BlockChain {
BlockLocation::CanonChain => { BlockLocation::CanonChain => {
block_hashes.insert(number, info.hash.clone()); block_hashes.insert(number, info.hash.clone());
}, },
BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => { BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => {
let ancestor_number = self.block_number(ancestor).unwrap(); let ancestor_number = self.block_number(ancestor).unwrap();
let start_number = ancestor_number + 1; let start_number = ancestor_number + 1;
for (index, hash) in route.iter().cloned().enumerate() { for (index, hash) in enacted.iter().cloned().enumerate() {
block_hashes.insert(start_number + index as BlockNumber, hash); block_hashes.insert(start_number + index as BlockNumber, hash);
} }
@ -661,11 +668,11 @@ impl BlockChain {
ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels())
.add_bloom(&header.log_bloom(), header.number() as usize) .add_bloom(&header.log_bloom(), header.number() as usize)
}, },
BlockLocation::BranchBecomingCanonChain { ref ancestor, ref route } => { BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => {
let ancestor_number = self.block_number(ancestor).unwrap(); let ancestor_number = self.block_number(ancestor).unwrap();
let start_number = ancestor_number + 1; let start_number = ancestor_number + 1;
let mut blooms: Vec<H2048> = route.iter() let mut blooms: Vec<H2048> = enacted.iter()
.map(|hash| self.block(hash).unwrap()) .map(|hash| self.block(hash).unwrap())
.map(|bytes| BlockView::new(&bytes).header_view().log_bloom()) .map(|bytes| BlockView::new(&bytes).header_view().log_bloom())
.collect(); .collect();
@ -825,7 +832,7 @@ mod tests {
use rustc_serialize::hex::FromHex; use rustc_serialize::hex::FromHex;
use util::hash::*; use util::hash::*;
use util::sha3::Hashable; use util::sha3::Hashable;
use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; use blockchain::{BlockProvider, BlockChain, BlockChainConfig, ImportRoute};
use tests::helpers::*; use tests::helpers::*;
use devtools::*; use devtools::*;
use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer}; use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
@ -943,10 +950,30 @@ mod tests {
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());
bc.insert_block(&b1, vec![]); let ir1 = bc.insert_block(&b1, vec![]);
bc.insert_block(&b2, vec![]); let ir2 = bc.insert_block(&b2, vec![]);
bc.insert_block(&b3a, vec![]); let ir3b = bc.insert_block(&b3b, vec![]);
bc.insert_block(&b3b, vec![]); let ir3a = bc.insert_block(&b3a, vec![]);
assert_eq!(ir1, ImportRoute {
enacted: vec![b1_hash],
retracted: vec![],
});
assert_eq!(ir2, ImportRoute {
enacted: vec![b2_hash],
retracted: vec![],
});
assert_eq!(ir3b, ImportRoute {
enacted: vec![b3b_hash],
retracted: vec![],
});
assert_eq!(ir3a, ImportRoute {
enacted: vec![b3a_hash],
retracted: vec![b3b_hash],
});
assert_eq!(bc.best_block_hash(), best_block_hash); assert_eq!(bc.best_block_hash(), best_block_hash);
assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0); assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0);

View File

@ -0,0 +1,119 @@
// 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/>.
//! Import route.
use util::hash::H256;
use blockchain::block_info::{BlockInfo, BlockLocation};
/// Import route for newly inserted block.
#[derive(Debug, PartialEq)]
pub struct ImportRoute {
/// Blocks that were invalidated by new block.
pub retracted: Vec<H256>,
/// Blocks that were validated by new block.
pub enacted: Vec<H256>,
}
impl ImportRoute {
pub fn none() -> Self {
ImportRoute {
retracted: vec![],
enacted: vec![],
}
}
}
impl From<BlockInfo> for ImportRoute {
fn from(info: BlockInfo) -> ImportRoute {
match info.location {
BlockLocation::CanonChain => ImportRoute {
retracted: vec![],
enacted: vec![info.hash],
},
BlockLocation::Branch => ImportRoute::none(),
BlockLocation::BranchBecomingCanonChain { mut enacted, retracted, .. } => {
enacted.push(info.hash);
ImportRoute {
retracted: retracted,
enacted: enacted,
}
}
}
}
}
#[cfg(test)]
mod tests {
use util::hash::H256;
use util::numbers::U256;
use blockchain::block_info::{BlockInfo, BlockLocation};
use blockchain::ImportRoute;
#[test]
fn import_route_none() {
assert_eq!(ImportRoute::none(), ImportRoute {
enacted: vec![],
retracted: vec![],
});
}
#[test]
fn import_route_branch() {
let info = BlockInfo {
hash: H256::from(U256::from(1)),
number: 0,
total_difficulty: U256::from(0),
location: BlockLocation::Branch,
};
assert_eq!(ImportRoute::from(info), ImportRoute::none());
}
#[test]
fn import_route_canon_chain() {
let info = BlockInfo {
hash: H256::from(U256::from(1)),
number: 0,
total_difficulty: U256::from(0),
location: BlockLocation::CanonChain,
};
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![],
enacted: vec![H256::from(U256::from(1))],
});
}
#[test]
fn import_route_branch_becoming_canon_chain() {
let info = BlockInfo {
hash: H256::from(U256::from(2)),
number: 0,
total_difficulty: U256::from(0),
location: BlockLocation::BranchBecomingCanonChain {
ancestor: H256::from(U256::from(0)),
enacted: vec![H256::from(U256::from(1))],
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
}
};
assert_eq!(ImportRoute::from(info), ImportRoute {
retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))],
enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))],
});
}
}

View File

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