storage insert works with indexed blocks
This commit is contained in:
parent
23b1c804e3
commit
6067d9996f
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue