storage insert works with indexed blocks

This commit is contained in:
NikVolf 2016-11-27 22:01:12 +03:00
parent 23b1c804e3
commit 6067d9996f
4 changed files with 86 additions and 23 deletions

View File

@ -1,5 +1,5 @@
use primitives::hash::H256;
use super::BlockLocation;
use super::{BlockLocation, IndexedBlock};
use chain;
use error::Error;
@ -46,4 +46,7 @@ pub trait BlockStapler {
/// insert block in the storage
fn insert_block(&self, block: &chain::Block) -> Result<BlockInsertedChain, Error>;
/// insert pre-processed block in the storage
fn insert_indexed_block(&self, block: &IndexedBlock) -> Result<BlockInsertedChain, Error>;
}

View File

@ -28,6 +28,22 @@ impl From<chain::Block> for IndexedBlock {
}
impl IndexedBlock {
pub fn new(header: chain::BlockHeader, transaction_index: Vec<(H256, chain::Transaction)>) -> Self {
let mut block = IndexedBlock {
header_hash: header.hash(),
header: header,
transactions: Vec::new(),
transaction_hashes: Vec::new(),
};
for (h256, tx) in transaction_index {
block.transactions.push(tx);
block.transaction_hashes.push(h256);
}
block
}
pub fn transactions(&self) -> IndexedTransactions {
IndexedTransactions {
position: 0,
@ -35,6 +51,10 @@ impl IndexedBlock {
}
}
pub fn transaction_hashes(&self) -> &[H256] {
&self.transaction_hashes
}
pub fn header(&self) -> &chain::BlockHeader {
&self.header
}
@ -42,6 +62,17 @@ impl IndexedBlock {
pub fn hash(&self) -> &H256 {
&self.header_hash
}
pub fn transaction_count(&self) -> usize {
self.transaction_hashes.len()
}
pub fn to_block(&self) -> chain::Block {
chain::Block::new(
self.header.clone(),
self.transactions.clone(),
)
}
}
pub struct IndexedTransactions<'a> {

View File

@ -6,7 +6,7 @@ use kvdb::{Database, DatabaseConfig};
use byteorder::{LittleEndian, ByteOrder};
use primitives::hash::H256;
use primitives::bytes::Bytes;
use super::{BlockRef, BestBlock, BlockLocation};
use super::{BlockRef, BestBlock, BlockLocation, IndexedBlock, IndexedTransactions};
use serialization::{serialize, deserialize};
use chain;
use parking_lot::RwLock;
@ -168,20 +168,41 @@ impl Storage {
})
}
fn block_by_hash(&self, h: &H256) -> Option<IndexedBlock> {
self.block_header_by_hash(h).map(|header| {
let tx_index =
self.block_transaction_hashes_by_hash(h)
.into_iter()
.filter_map(|tx_hash| {
self.transaction_bytes(&tx_hash)
.map(|tx_bytes| {
(
tx_hash,
deserialize::<_, chain::Transaction>(tx_bytes.as_ref())
.expect("Error deserializing transaction, possible db corruption"),
)
})
})
.collect();
IndexedBlock::new(header, tx_index)
})
}
/// update transactions metadata in the specified database transaction
fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &[chain::Transaction])
fn update_transactions_meta(&self, context: &mut UpdateContext, number: u32, accepted_txs: &mut IndexedTransactions)
-> Result<(), Error>
{
if let Some(accepted_tx) = accepted_txs.iter().next() {
if let Some((accepted_hash, accepted_tx)) = accepted_txs.next() {
context.meta.insert(
accepted_tx.hash(),
accepted_hash.clone(),
TransactionMeta::new_coinbase(number, accepted_tx.outputs.len())
);
}
for accepted_tx in accepted_txs.iter().skip(1) {
for (accepted_hash, accepted_tx) in accepted_txs {
context.meta.insert(
accepted_tx.hash(),
accepted_hash.clone(),
TransactionMeta::new(number, accepted_tx.outputs.len())
);
@ -294,8 +315,8 @@ impl Storage {
}
fn canonize_block(&self, context: &mut UpdateContext, at_height: u32, hash: &H256) -> Result<(), Error> {
let transactions = self.block_transactions_by_hash(hash);
try!(self.update_transactions_meta(context, at_height, &transactions));
let block = try!(self.block_by_hash(hash).ok_or(Error::unknown_hash(hash)));
try!(self.update_transactions_meta(context, at_height, &mut block.transactions()));
// only canonical blocks are allowed to wield a number
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(at_height), &**hash);
@ -412,8 +433,12 @@ impl BlockProvider for Storage {
impl BlockStapler for Storage {
/// insert pre-processed block in the storage
fn insert_block(&self, block: &chain::Block) -> Result<BlockInsertedChain, Error> {
self.insert_indexed_block(&block.clone().into())
}
fn insert_indexed_block(&self, block: &IndexedBlock) -> Result<BlockInsertedChain, Error> {
// ! lock will be held during the entire insert routine
let mut best_block = self.best_block.write();
@ -428,39 +453,38 @@ impl BlockStapler for Storage {
let mut new_best_number = match best_block.as_ref().map(|b| b.number) {
Some(best_number) => {
if block.hash() == new_best_hash { best_number + 1 }
if block.hash() == &new_best_hash { best_number + 1 }
else { best_number }
},
None => 0,
};
let tx_space = block.transactions().len() * 32;
let tx_space = block.transaction_count() * 32;
let mut tx_refs = Vec::with_capacity(tx_space);
for tx in block.transactions() {
let tx_hash = tx.hash();
tx_refs.extend(&*tx_hash);
for (tx_hash, tx) in block.transactions() {
tx_refs.extend(&**tx_hash);
context.db_transaction.put(
Some(COL_TRANSACTIONS),
&*tx_hash,
&**tx_hash,
&serialize(tx),
);
}
context.db_transaction.put(Some(COL_BLOCK_TRANSACTIONS), &*block_hash, &tx_refs);
context.db_transaction.put(Some(COL_BLOCK_TRANSACTIONS), &**block_hash, &tx_refs);
context.db_transaction.put(
Some(COL_BLOCK_HEADERS),
&*block_hash,
&**block_hash,
&serialize(block.header())
);
// the block is continuing the main chain
let result = if best_block.as_ref().map(|b| b.number) != Some(new_best_number) {
try!(self.update_transactions_meta(&mut context, new_best_number, block.transactions()));
try!(self.update_transactions_meta(&mut context, new_best_number, &mut block.transactions()));
context.db_transaction.write_u32(Some(COL_META), KEY_BEST_BLOCK_NUMBER, new_best_number);
// updating main chain height reference
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(new_best_number), &*block_hash);
context.db_transaction.write_u32(Some(COL_BLOCK_NUMBERS), &*block_hash, new_best_number);
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(new_best_number), &**block_hash);
context.db_transaction.write_u32(Some(COL_BLOCK_NUMBERS), &**block_hash, new_best_number);
BlockInsertedChain::Main
}
@ -473,10 +497,10 @@ impl BlockStapler for Storage {
Ok(Some(mut reorg)) => {
// if so, we have new best main chain block
new_best_number = reorg.height + 1;
new_best_hash = block_hash;
new_best_hash = block_hash.clone();
// and we canonize it also by provisioning transactions
try!(self.update_transactions_meta(&mut context, new_best_number, block.transactions()));
try!(self.update_transactions_meta(&mut context, new_best_number, &mut block.transactions()));
context.db_transaction.write_u32(Some(COL_META), KEY_BEST_BLOCK_NUMBER, new_best_number);
context.db_transaction.put(Some(COL_BLOCK_HASHES), &u32_key(new_best_number), &*new_best_hash);
context.db_transaction.write_u32(Some(COL_BLOCK_NUMBERS), &*new_best_hash, new_best_number);

View File

@ -2,7 +2,8 @@
use super::{
BlockRef, Store, Error, BestBlock, BlockLocation, BlockInsertedChain, BlockProvider,
BlockStapler, TransactionMetaProvider, TransactionProvider, AsTransactionProvider
BlockStapler, TransactionMetaProvider, TransactionProvider, AsTransactionProvider,
IndexedBlock,
};
use chain::{self, Block};
use primitives::hash::H256;
@ -111,6 +112,10 @@ impl BlockProvider for TestStorage {
}
impl BlockStapler for TestStorage {
/// insert pre-processed block in the storage
fn insert_indexed_block(&self, block: &IndexedBlock) -> Result<BlockInsertedChain, Error> {
self.insert_block(&block.to_block())
}
fn insert_block(&self, block: &chain::Block) -> Result<BlockInsertedChain, Error> {
let hash = block.hash();