keep track of first block in blockchain (#1937)

This commit is contained in:
Robert Habermeier 2016-08-18 22:01:57 +02:00 committed by Arkadiy Paronyan
parent d7c184bd72
commit 0e0cc20d84
2 changed files with 51 additions and 1 deletions

View File

@ -41,6 +41,16 @@ pub trait BlockProvider {
/// (though not necessarily a part of the canon chain). /// (though not necessarily a part of the canon chain).
fn is_known(&self, hash: &H256) -> bool; fn is_known(&self, hash: &H256) -> bool;
/// Get the first block which this chain holds.
/// Any queries of blocks which precede this one are not guaranteed to
/// succeed.
fn first_block(&self) -> H256;
/// Get the number of the first block.
fn first_block_number(&self) -> BlockNumber {
self.block_number(&self.first_block()).expect("First block always stored; qed")
}
/// Get raw block data /// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes>; fn block(&self, hash: &H256) -> Option<Bytes>;
@ -144,6 +154,7 @@ impl bc::group::BloomGroupDatabase for BlockChain {
pub struct BlockChain { pub struct BlockChain {
// All locks must be captured in the order declared here. // All locks must be captured in the order declared here.
blooms_config: bc::Config, blooms_config: bc::Config,
first_block: H256,
best_block: RwLock<BestBlock>, best_block: RwLock<BestBlock>,
@ -174,6 +185,10 @@ impl BlockProvider for BlockChain {
self.db.exists_with_cache(db::COL_EXTRA, &self.block_details, hash) self.db.exists_with_cache(db::COL_EXTRA, &self.block_details, hash)
} }
fn first_block(&self) -> H256 {
self.first_block
}
/// Get raw block data /// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes> { fn block(&self, hash: &H256) -> Option<Bytes> {
match (self.block_header_data(hash), self.block_body(hash)) { match (self.block_header_data(hash), self.block_body(hash)) {
@ -325,11 +340,12 @@ impl BlockChain {
// 400 is the avarage size of the key // 400 is the avarage size of the key
let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400); let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400);
let bc = BlockChain { let mut bc = BlockChain {
blooms_config: bc::Config { blooms_config: bc::Config {
levels: LOG_BLOOMS_LEVELS, levels: LOG_BLOOMS_LEVELS,
elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX, elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX,
}, },
first_block: H256::zero(),
best_block: RwLock::new(BestBlock::default()), best_block: RwLock::new(BestBlock::default()),
block_headers: RwLock::new(HashMap::new()), block_headers: RwLock::new(HashMap::new()),
block_bodies: RwLock::new(HashMap::new()), block_bodies: RwLock::new(HashMap::new()),
@ -370,7 +386,9 @@ impl BlockChain {
batch.write(db::COL_EXTRA, &hash, &details); batch.write(db::COL_EXTRA, &hash, &details);
batch.write(db::COL_EXTRA, &header.number(), &hash); batch.write(db::COL_EXTRA, &header.number(), &hash);
batch.put(db::COL_EXTRA, b"best", &hash); batch.put(db::COL_EXTRA, b"best", &hash);
batch.put(db::COL_EXTRA, b"first", &hash);
bc.db.write(batch).expect("Low level database error. Some issue with disk?"); bc.db.write(batch).expect("Low level database error. Some issue with disk?");
hash hash
} }
@ -382,6 +400,34 @@ impl BlockChain {
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty; let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
let best_block_rlp = bc.block(&best_block_hash).unwrap(); let best_block_rlp = bc.block(&best_block_hash).unwrap();
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map_or(Vec::new(), |v| v.to_vec());
// binary search for the first block.
if raw_first.is_empty() {
let (mut f, mut hash) = (best_block_number, best_block_hash);
let mut l = 0;
loop {
if l >= f { break; }
let step = (f - l) >> 1;
let m = l + step;
match bc.block_hash(m) {
Some(h) => { f = m; hash = h },
None => { l = m + 1 },
}
}
let batch = db.transaction();
batch.put(db::COL_EXTRA, b"first", &hash);
db.write(batch).expect("Low level database error.");
bc.first_block = hash;
} else {
bc.first_block = H256::from_slice(&raw_first);
}
// and write them // and write them
let mut best_block = bc.best_block.write(); let mut best_block = bc.best_block.write();
*best_block = BestBlock { *best_block = BestBlock {

View File

@ -284,6 +284,10 @@ mod tests {
self.blocks.contains_key(hash) self.blocks.contains_key(hash)
} }
fn first_block(&self) -> H256 {
unimplemented!()
}
/// Get raw block data /// Get raw block data
fn block(&self, hash: &H256) -> Option<Bytes> { fn block(&self, hash: &H256) -> Option<Bytes> {
self.blocks.get(hash).cloned() self.blocks.get(hash).cloned()