Merge pull request #645 from ethcore/import_route
blockchain import_route
This commit is contained in:
commit
16e12b1ae5
@ -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>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
_ => {
|
||||||
|
let retracted = route.blocks.iter().take(route.index).cloned().collect::<Vec<H256>>();
|
||||||
|
|
||||||
|
BlockLocation::BranchBecomingCanonChain {
|
||||||
ancestor: route.ancestor,
|
ancestor: route.ancestor,
|
||||||
route: route.blocks.into_iter().skip(route.index).collect()
|
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);
|
||||||
|
119
ethcore/src/blockchain/import_route.rs
Normal file
119
ethcore/src/blockchain/import_route.rs
Normal 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))],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user